Spring boot2 unit test

Keywords: Programming Spring Maven SSL

Introduce maven dependency

powermock is introduced to solve the problem of static method mock.

<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-module-junit4</artifactId>
    <version>2.0.2</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-api-mockito2</artifactId>
    <version>2.0.2</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>2.28.2</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.assertj</groupId>
    <artifactId>assertj-core</artifactId>
    <version>3.11.1</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-all</artifactId>
    <version>2.0.2-beta</version>
    <scope>test</scope>
</dependency>

Building Unit Test Directory

Like the standard maven unit test directory, add application.yml to the resources directory as follows:

spring:
  profiles:
    active: test

---
spring:
  profiles: test

dc:
  security:
    auditlog:
      module: "System Manage"        #Module name
logging:
  level:
    root: INFO

Abstract test parent class

@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(SpringRunner.class)
@PowerMockIgnore({"javax.management.*", "javax.net.ssl.*"})
@SpringBootTest
@ActiveProfiles("test")
public abstract class AbstractSpringTest {
    @MockBean
    protected ISecurityContextService securityContextService;
    @SpyBean
    protected RestTemplate restTemplate;
    @Autowired
    protected AuditLogProperties properties;
}

Actual unit test case

@PrepareForTest({SecurityContextHolder.class, ClientContextHolder.class})
public class ApiOperationLogServiceTest extends AbstractSpringTest {

    private ApiOperationLogService operationLogService;

    @Before
    public void setUp() throws Exception {
        System.out.println("###################test start##########################");
        operationLogService = new ApiOperationLogService(properties, restTemplate);
    }

    @After
    public void tearDown() throws Exception {
        System.out.println("###################test end##########################");
    }

    @Test
    public void save() {
        ResultVo resultVo = new ResultVo();
        resultVo.setResultCode(0);
        resultVo.setResultMessage("save log success");
        ResponseEntity<ResultVo> response = new ResponseEntity<>(resultVo, HttpStatus.OK);
        doReturn(response).when(restTemplate).exchange(eq(properties.getOperationLogUrl()), eq(HttpMethod.POST),
            isA(HttpEntity.class), eq(ResultVo.class));
        operationLogService.save(new OperationLog());
    }

    @Test
    public void testLoadOperatorId() {
        // PowerMockito Pile Driving, Static Simulation Method
        PowerMockito.mockStatic(SecurityContextHolder.class);
        SecurityContextImpl securityContext = new SecurityContextImpl();
        securityContext.setAuthentication(
            new UsernamePasswordAuthenticationToken("xiongneng", "123456"));
        PowerMockito.when(SecurityContextHolder.getContext()).thenReturn(securityContext);
        assertEquals(operationLogService.loadOperatorId(), "xiongneng");
    }

    @Test
    public void testLoadClientIpWhenRemoteUserIp() {
        // PowerMockito pile driving, simulated static method
        PowerMockito.mockStatic(ClientContextHolder.class);
        ClientContext clientContext = new ClientContext();
        clientContext.setClientIP("192.168.20.22");
        clientContext.setRemoteUserIP("30.200.12.22");
        PowerMockito.when(ClientContextHolder.getContext()).thenReturn(clientContext);
        assertEquals(operationLogService.loadClientIp(), "30.200.12.22");
    }

    @Test
    public void testLoadClientIpWhenNoRemoteUserIp() {
        // PowerMockito pile driving, simulated static method
        PowerMockito.mockStatic(ClientContextHolder.class);
        ClientContext clientContext = new ClientContext();
        clientContext.setClientIP("192.168.20.22");
        PowerMockito.when(ClientContextHolder.getContext()).thenReturn(clientContext);
        assertEquals(operationLogService.loadClientIp(), "192.168.20.22");
    }
}

Differences between MockBean and SpyBean

There are two differences between spy object and mock object:

1. The difference of default behavior

For the method without specified mock, spy will call the real method by default. For the method with return value, it will return the real return value. For the method with return value, it will not execute by default. For the method with return value, it will return null by default.

2. Different ways of using mock

The use of mock objects, spy objects use this method directly, so it can not be used in this way, such as:

Mockito.when(obj.domethod(parm1, param2)).thenReturn(result);

For the usage of spy objects, do and other methods should be executed first. mock objects can also be used in this way, such as:

Mockito.doReturn(info).when(obj).domethod(param1, param2);

@ The difference between Spy and @SpyBean, @Mock and @MockBean

  1. Objects generated by spy and mock are not managed by spring
  2. When the spy calls the real method, other beans cannot be injected. To use the injection, use the spy bean.
  3. The objects generated by SpyBean and MockBean are managed by spring, which is equivalent to automatically replacing the injection of corresponding type beans, such as @ Autowired.

Simulation void method

There are two ways to simulate the void method, one is to throw an exception, the other is to specify the execution process of void through Answer.

Throw the expected exception:

doThrow(RuntimeException.class).when(daoMock).updateEmail(any(Customer.class), any(String.class));

Specify the void execution process:

doAnswer((Answer<Void>) invocation -> {
    Object[] args = invocation.getArguments();
    System.out.println("restTemplate.exchange called with arguments: " + Arrays.toString(args));
    return null;
}).when(restTemplate).exchange(anyString(), eq(HttpMethod.POST),
    isA(HttpEntity.class), eq(ResultVo.class));

// Implement real methods
doAnswer(Answers.CALLS_REAL_METHODS.get()).when(mock).voidMethod(any(SomeParamClass.class));

Posted by leeharvey09 on Tue, 15 Oct 2019 03:50:03 -0700