Model-View-Presenter and its implementation in ASP.NET - Part 2
In this post, we will briefly explore the challenges that arise when automating UI tests and discuss why adopting a new pattern may be necessary in certain situations.
The ideas and opinions shared here are my own and open to challenge.
Why are tests essential in a software application ?
We won't go into great detail on this question, as the importance of automated tests is widely acknowledged. Tests help ensure non-regression, allowing us to release new versions more frequently and with greater confidence.
Consider, for example, a basic requirement for a Payment class where we need to calculate the VAT for a given price. The corresponding C# code might look like this.
1public class Payment
2{
3 public decimal Price { get; private set; }
4
5 public Payment(decimal price)
6 {
7 Price = price;
8 }
9
10 public decimal PriceVATIncluded => Price * 1.2;
11}
The corresponding test class should ressemble to the following (in NUnit).
1public class PaymentTests
2{
3 [Test]
4 public void CheckVATIsCorrectlyCalculated()
5 {
6 // Arrange
7 var payment = new Payment(100.0);
8
9 // Act
10 var priceWithVAT = payment.PriceVATIncluded;
11
12 // Assert
13 Assert.AreEqual(120.0, priceWithVAT);
14 }
15}
This code is quite simple and, in itself, not particularly interesting, but it's something we will inevitably encounter at some point in the software lifecycle. In this example, it's evident that tests for DOMAIN OBJECTS can be relatively easy to maintain.
Why is UI so difficult to test ?
We've just seen that testing domain classes is often straightforward (though not necessarily easy). In contrast, testing UI classes is frequently quite challenging.
User interfaces often involve intricate interactions between elements, such as buttons, forms, and dynamic content.
UIs can change frequently due to design updates, which might break existing tests or require constant adjustments to test scripts.
Testing UIs requires managing and validating different states of the application, including user inputs, error messages, and loading conditions.
Automated tests often struggle with visual verification, such as ensuring that elements are correctly positioned, styled, and responsive.
For example, consider a simple login page where users attempt to authenticate. The code might resemble the following.
1public class LoginView
2{
3 // ...
4
5 public Task btnLoginButton_Submit(EventArgs e)
6 {
7 var username = txtUserName.Text;
8 var password = txtPassword.Text;
9
10 if (_userRepository.Authenticate(userName, password))
11 {
12 txtWelcome = "Welcome, you are logged in !";
13 btnSeeMoreFeatures.Enabled = true;
14 }
15 else
16 {
17 txtWelcome = "Sorry !";
18 }
19 }
20}
To properly test this code, we need to simulate a submit event (which can be complex) and then verify that the various components have updated correctly. Even if we had a tool that could extract this data directly from the HTML, we would still face race conditions, as checking the new values too soon could lead to inaccurate results.
Additionally, we are not performing visual verification. Are the textboxes rendered correctly ? Is the design responsive ? These questions require careful attention. How to address them ?
Model-View-Presenter to the rescue
In the previous description of UI tests, it's important to recognize that there are two types of tests: one purely focuses on business logic (e.g., when I click the Submit button and authentication is successful, a welcome message is displayed; otherwise, an error message is shown), while the other deals with visual effects (e.g., the button should be 200px wide and positioned next to the text box).
The second type (dealing with visual effects), is more challenging to handle and typically requires specialized tools like Selenium or Katalon (see our article here for more details). However, the first type, which focuses on business logic, can be encapsulated in specific classes designed for maintainability and testability. This is where the MVP pattern comes into play.
The MVP design pattern involves delegating all business logic that would typically be part of a UI component (the view) to a dedicated class known as the presenter. This presenter interacts with the model to validate rules or invoke more complex services, and then updates the UI as needed. As a result, the view becomes a simple entity that only communicates with the presenter when necessary: it is an humble object.
Humble Object is a way to bring the logic of these hard-toinstantiate objects under test in a cost-effective manner.
Meszaros xUnit Test Patterns
What is the model ?
There's no need to go into detail on this topic: the model is simply the representation of the domain within a programming language. It encompasses the business rules and the complex logic that exists between different classes.
In a microservices architecture, each bounded context (microservice) typically has its own model. Consequently, a UI component might need to display data from multiple models.
The model is often quite straightforward to test.
What is the view ?
A model serves little purpose if it is not displayed or utilized by another client. In this case, it is the view's responsibility to allow the user to interact with the model through various visual elements such as text boxes, buttons, and forms. These components collectively constitute the UI.
The view can contain complex logic: even in our simple example, the Submit button must retrieve values from two text boxes, validate authentication, and display a message accordingly. This business logic is intertwined with the code that manages visual effects.
We could conclude here and proceed with this approach: for small applications or proofs of concept, having just a model and a view interacting with it might suffice. However, it’s important to be aware of the issues this approach can introduce, as mentioned earlier. Other concerns also fall under this topic: for example, the view often has to handle multithreading. These factors contribute to making the UI highly unpredictable and, consequently, very difficult to test.
What is the presenter ?
The role of the presenter is specifically to offload the business logic into a separate class, making testing more streamlined. The visual layout remains within the view and should still be tested using traditional UI testing tools.
The presenter allows the view to offload the business logic that complicates it, leaving it focused solely on visual effects.

The presenter serves as an intermediary between the model and the view. Additionally, the presenter can update the view as needed, whether based on its own decisions or changes in the model. Importantly, the presenter can be instantiated in test classes, facilitating testing and ensuring that business logic is properly validated.
The view no longer interacts directly with the model and is unaware of it. Instead, the presenter handles communication with the model and extracts the necessary information.
Having provided a brief overview of the MVP pattern, let's now examine it in greater detail and see it in action.
Model-View-Presenter and its implementation in ASP.NET - Part 3