Unit Testing refers to the testing work of checking the correctness of the smallest testable unit in the software or project. A unit is an artificially specified minimum testable functional module, which can be a module, a function or a class. Unit testing needs to be done in isolation from module development.
After the program development is completed, we often cannot guarantee that the program is 100% correct. By writing unit tests, we can define our input and output programs through automated test programs, check the results of each Case through assertions, and detect our program. To improve the correctness, stability, and reliability of the program and save program development time. The main unit testing frameworks we use in the project include Spring-Boot-Test
TestNG
, PowerMock
, etc.
TestNG
, that is, Testing, Next Generation
, the next generation testing technology, is a testing framework built based on the ideas of JUnit and NUnit that uses annotations to strengthen testing functions, namely It can be used for unit testing or integration testing.
PowerMock
is also a unit test simulation framework, which is an extension based on other unit test simulation frameworks. By providing a customized class loader and the application of some bytecode tampering techniques, PowerMock
now supports simulation of static methods, constructors, private methods and Final methods, and removes the static initialization process. and other powerful functions.
Commonly used annotations
1. TestNG annotations
@BeforeSuite
Runs only once before all tests of the suite have run on the annotated method@AftereSuite
Runs only once after all tests of the suite have been run on the annotated method@BeforeClass
runs before calling the first test method of the current class. Annotated methods only run once.@AftereClass
runs after calling the first test method of the current class. Annotated methods only run once.@BeforeMethod
annotated method will be run before each test method@AfterMethod
annotated method will be run after each test method@BeforeTest
The annotated method will be run before all test methods belonging to the class within the test tag are run.@AfterTest
The annotated method will be run after all test methods belonging to the class within the test tag are run.@DataProvider
Marks a method to provide data for the test method. The annotation method must return anObject [] []
, where eachObject []
can be assigned to the parameter list of the test method.@Test
methods that want to receive data from thisDataProvider
need to use adataProvider
name equal to this annotation name@Parameters
describes how to pass parameters to the@Test
method; suitable for parameterized value passing in xml mode@Test
marks a class or method as part of the test. If this mark is placed on a class, all public methods of the class will be used as test methods.
2. PowerMock annotations
- The
@Mock
annotation is actually the abbreviation of the Mockito.mock() method, we only use it in the test class; @InjectMocks
actively injects existing mock objects into beans by name, but no exception will be thrown if the injection fails;@Spy
encapsulates a real object so that the object’s behavior can be tracked and set like other mock objects;
Now I have also found a lot of test friends and created a communication group to share technology, sharing a lot of technical documents and video tutorials we collected. If you don’t want to experience the feeling of not being able to find resources when studying on your own, having no one to answer your questions, and persisting for a few days before giving up. You can join us to communicate. And there are many technical experts who have made certain achievements in automation, performance, security, test development, etc. Share their experience, and also share many live lectures and technical salons You can learn for free! Focus on it! Open source! ! ! QQ group number: 110685036
Example code
1. Add pom.xml dependency
Taking the Spring-Boot project as an example, first we need to add TestNG
+ ProwerMock
dependencies as follows:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.testng</groupId> <artifactId>testng</artifactId> <version>${testng.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-api-mockito2</artifactId> <version>${powermock.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-module-junit4</artifactId> <version>${powermock.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-module-testng</artifactId> <version>${powermock.version}</version> <scope>test</scope> </dependency>
2. Add unit test
Add test code
import com.test.testng.dto.OrderDto; import com.test.testng.dto.UserDto; import org.mockito.*; import org.powermock.modules.testng.PowerMockTestCase; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.when; public class OrderServiceTest extends PowerMockTestCase { @BeforeMethod public void before() { MockitoAnnotations.openMocks(this); } @InjectMocks private OrderService orderService; @Mock private UserService userService; // normal test @Test public void testCreateOrder() { //1. mock method start UserDto userDto = new UserDto(); userDto.setId(100); when(userService.get()).thenReturn(userDto); //2. call business method OrderDto order = orderService.createOrder(new OrderDto()); //3.assert assertEquals(order.getId(), 100); } //Exception test @Test public void testCreateOrderEx() { //1. mock method start when(userService.get()).thenThrow(new RuntimeException()); Exception exception = null; try { //2. call business method orderService.createOrder(new OrderDto()); } catch (RuntimeException e) { exception = e; } //3.assert assertNotNull(exception); } }
Common Mock methods
1. Mock static method
//Static method UserDto dto = new UserDto(); dto.setId(100000); PowerMockito.mockStatic(UserService.class); PowerMockito.when(UserService.loginStatic()).thenReturn(dto); UserDto userDto = UserService.loginStatic(); assertEquals(100000, userDto.getId().intValue());
2. Mock private properties
//Field assignment ReflectionTestUtils.setField(orderService, "rateLimit", 99);
3. Mock private method
//Mock private methods MemberModifier.stub(MemberMatcher.method(UserService.class, "get1")).toReturn(new UserDto()); //Test private method Method method = PowerMockito.method(UserService.class, "get1", Integer.class); Object userDto = method.invoke(userService, 1); assertTrue(userDto instanceof UserDto);
Advanced use
1. Parameterized batch testing
When there is a lot of test data, we can generate a data source through @DataProvider
and use the data through @Test(dataProvider = "xxx")
, as shown below:
import com.test.testng.BaseTest; import com.test.testng.dto.UserDto; import org.mockito.InjectMocks; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import static org.testng.Assert.assertFalse; import static org.testng.AssertJUnit.assertTrue; public class UserServiceTest2 extends BaseTest { @InjectMocks private UserService userService; //Define data source @DataProvider(name = "test") public static Object[][] userList() { UserDto dto1 = new UserDto(); UserDto dto2 = new UserDto(); dto2.setSex(1); UserDto dto3 = new UserDto(); dto3.setSex(1); dto3.setFlag(1); UserDto dto4 = new UserDto(); dto4.setSex(1); dto4.setFlag(1); dto4.setAge(1); return new Object[][] {<!-- -->{dto1, null}, {dto2, null}, {dto3, null}, {dto4, null}}; } // Correct scenario @Test public void testCheckEffectiveUser() { UserDto dto = new UserDto(); dto.setSex(1); dto.setFlag(1); dto.setAge(18); boolean result = userService.checkEffectiveUser(dto); assertTrue(result); } // error scenario @Test(dataProvider = "test") public void testCheckEffectiveUser(UserDto dto, Object object) { boolean result = userService.checkEffectiveUser(dto); assertFalse(result); } }
Case:
- Determine valid users: age is greater than 18 and sex = 1 and flag = 1
public boolean checkEffectiveUser(UserDto dto) { // Determine valid users: age is greater than 18 and sex = 1 and flag = 1 return Objects.equals(dto.getSex(), 1) & amp; & amp; Objects.equals(dto.getFlag(), 1) & amp; & amp; dto.getAge() != null & amp; & amp; dto.getAge() >= 18; }
- Split logic. Convert this into the simplest if … else statement. Then add unit tests as follows:
public boolean checkEffectiveUser(UserDto dto) { if (!Objects.equals(dto.getSex(), 1)) { return false; } if (!Objects.equals(dto.getFlag(), 1)) { return false; } if (dto.getAge() == null) { return false; } if (dto.getAge() < 18) { return false; } return true; }
- After splitting, we can see that we only need 5 unit tests to achieve full coverage.
public class UserServiceTest extends BaseTest { @InjectMocks private UserService userService; // Overwrite the first return @Test public void testCheckEffectiveUser_0() { UserDto dto =new UserDto(); boolean result = userService.checkEffectiveUser(dto); assertFalse(result); } // Overwrite the second return @Test public void testCheckEffectiveUser_1() { UserDto dto =new UserDto(); dto.setSex(1); boolean result = userService.checkEffectiveUser(dto); assertFalse(result); } // Overwrite the third return @Test public void testCheckEffectiveUser_2() { UserDto dto =new UserDto(); dto.setSex(1); dto.setFlag(1); boolean result = userService.checkEffectiveUser(dto); assertFalse(result); } // Overwrite the fourth return @Test public void testCheckEffectiveUser_3() { UserDto dto =new UserDto(); dto.setSex(1); dto.setFlag(1); dto.setAge(1); boolean result = userService.checkEffectiveUser(dto); assertFalse(result); } // Overwrite the fifth return @Test public void testCheckEffectiveUser_4() { UserDto dto =new UserDto(); dto.setSex(1); dto.setFlag(1); dto.setAge(18); boolean result = userService.checkEffectiveUser(dto); assertTrue(result); } }
- Single test coverage detection detection
3. Verify method parameters through assertions
assert
: Assertion is a reserved word of Java, used to debug the program, followed by a logical operation expression, as follows:
int a = 0, b = 1; assert a == 0 & amp; & amp; b == 0; // How to use: javac compiles the source file, and then java -ea class file name.
- In Spring-Boot, you can use the Assert class method provided by Spring to verify the parameters from the front end, such as:
// Check age >= 18 years old public boolean checkUserAge(UserDto dto){ Assert.notNull(dto.getAge(), "User age cannot be null"); Assert.isTrue(dto.getAge() >= 18, "User age cannot be less than 18 years old"); return Boolean.TRUE; }
- If it needs to be converted into a unified corresponding message returned by
rest api
, we can pass:
@ControllerAdvice public class GlobalExceptionHandler { @ResponseBody @ExceptionHandler(value = IllegalArgumentException.class) public Response<String> handleArgError(IllegalArgumentException e){ return new Response().failure().message(e.getMessage()); } }
Summary
In principle, we should follow the following principles during the design process of functional modules (refer to “Software Engineering-Structured Design Guidelines”):
- Moderately sized module
- Proper system call depth
- More fan-in, less fan-out (increase reuse, reduce dependence)
- Single entrance, single exit
- The scope of the module should be within the module
- Functionality should be predictable
- High cohesion, low coupling
- System decomposition is hierarchical
- Less data redundancy
Finally: You can get a 216-page software test engineer interview guide document for free on my VX official account: [Automated Test Veteran]. And the corresponding video learning tutorials are shared for free! , which includes basic knowledge, Linux essentials, Shell, Internet program principles, Mysql database, packet capture tool topics, interface testing tools, advanced testing – Python programming, Web automated testing, APP automated testing, interface automated testing, testing Advanced continuous integration, test architecture development, test framework, performance testing, security testing, etc.
Friends who like software testing, if my blog is helpful to you and if you like the content of my blog, please “like”, “comment” and “favorite” with one click!