📜 ⬆️ ⬇️

Domain Object with Lombok: Battle Classics

Domain Object ( Russian “Domain Object” ) is one of the most popular approaches to using test data directly in script logic. At the moment, it is one of the most popular and popular approaches, due to its simplicity, clarity and consistency.

Let's apply in all types of automation of functional testing (End-to-End, API, Integration), regardless of the platform being tested, be it Web, Mobile, or Desktop.
IMPORTANT : Do not confuse Domain Object with Data Transfer Object (DTO) . These are completely different approaches that are applied in different areas.
What is its essence?

From the other name of the approach - “Business Object” - it becomes clear that this is a kind of abstraction, which is a model and description of the object, which is important for understanding and functioning of the business logic of the application . He is not able to perform any functions, except for the “transfer” of the fields and their values ​​to one specific business unit.
image
')


What it looks like


As an example, take any application that provides for the creation of a user account. It is the user that becomes our domain object. In almost all cases, the user must have a login and password:

//    User public class User { // ,  User    Login private String login; // ,  User    Password private String password; } 

Especially attentive will notice that all internal fields are private. Setting and reading values ​​directly from the fields of an object is considered bad practice. Instead, it is customary to use the well-known getters and setters:

 public class User { private String login; private String password; //      login public void setLogin(String login) { this.login = login; } //     login public String getLogin() { return this.login; } //    public void setPassword(String password) { this.password = password; } public String getPassword() { return this.password; } } 

Now, we have access to the fields, and can set and read their values. But in this example, we only use two fields. And what happens if these fields will be fifteen? True, the User class will grow to unprecedented sizes, thanks to the infinite copy-paste of getters and setters. How are we going to deal with it?



Magic lombok


This is where Project Lombok comes to the rescue - a popular library that allows you to reduce the code several times, avoid copy / paste-suffering, and significantly reduce the amount of time to write Data Object-classes. Some useful links:


What does he do? Automatically creates getters and setters for all fields of a class, by assigning it the appropriate annotation:

 import lombok.Getter; import lombok.Setter; //       User @Getter //       User @Setter public class User { private String login; private String password; } 

Simple, fast, convenient. Thus, our code becomes much more readable, classes - more concise, and development - faster.



We apply in the test


A good test is a test that clearly separates test data, test logic, and its implementation.

Let's try to log in our user. Create a class with test data, and “fill” them with a new User:

 //  Test Data  public class TestDataUser { //  private-    private final static String DEFAULT_LOGIN = "vasiliy_pupkin"; private final static String DEFAULT_PASSWORD = "q1w2e3"; //        public static User getDefaultUser() { //  ""  User user = new User(); //      Login user.setLogin(DEFAULT_LOGIN); //      Password user.setPassword(DEFAULT_PASSWORD); //    User,     return user; } } 

We describe the model of the login page:

 public class LoginPage { //  public- ,    User public void loginUser(User user) { //          enterLogin() enterLogin(user.getLogin()); //    enterPassword(user.getPassword()); } private void enterLogin(String login) { this.loginInput.sendKeys(login); } private void enterPassword(String password) { this.passwordInput.sendKeys(password); } } 

It remains only to implement the test class:

 public class LoginTest { @Test public void loginAsDefaultUser() { //    credentials   User user = TestDataUser.getDefaultUser(); //  Login- LoginPage loginPage = new LoginPage(); // ,     loginPage.loginUser(user); } } 

Done! You are wonderful!


Let's sum up


In the final we get a neat project architecture, with a clear separation of logic, data, and implementation. Lombok helps get rid of code duplication, Domain Object fits perfectly into the Page Object philosophy, and code support becomes a pleasure.

Should there be cons?

  1. Immunity. Or rather, its absence. In this, this approach using Lombok loses to the main competitor - Builder ( article on Habré ). But, in my opinion, the above code is more “clean”, understandable, and aesthetically pleasing, compared to the endless chain in the builder and the piling up of methods in the Object class.
  2. Increase complexity where it is not needed. Not so much a minus as a small reminder. Any approach or pattern has problems and should solve some problem. You should not try to use the Data Object in a unit test, which only checks that 2 + 2 = 4.

Thank you very much for your attention. I would be happy reviews and criticism.

PS Tell us in the comments what approaches you use in your work. It will be very interesting to read.

Source: https://habr.com/ru/post/442606/


All Articles