JUnit 5 单元测试实践

JUnit 5 单元测试实践

Mock

使用 MockitoExtension,即可以使用 @Mock 注解。

import org.junit.jupiter.api.Assertions;  
import org.junit.jupiter.api.Test;  
import org.junit.jupiter.api.extension.ExtendWith;  
import org.mockito.Mock;  
import org.mockito.junit.jupiter.MockitoExtension;


@ExtendWith(MockitoExtension.class)  
public class MyTest {
    @Mock  
    private TaggingService taggingService;

    @Test
    public void test() {
        when(taggingService.tagging(eq("A"), any())).thenReturn(2);
        Assertions.assertEquals(taggingService.tagging("A"), 2);
    }
}

Spring

使用 SpringExtension,配合@MockBean,可以在需要注入的地方使用 mock bean。

import org.junit.jupiter.api.Test;  
import org.junit.jupiter.api.extension.ExtendWith;  
import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.boot.test.context.SpringBootTest;  
import org.springframework.boot.test.mock.mockito.MockBean;  
import org.springframework.test.context.junit.jupiter.SpringExtension;

@ExtendWith(SpringExtension.class)  
@SpringBootTest(classes = { NodeMapperImpl.class })  
public class UnitSerializeTest  {
    @Autowired
    NodeMapper nodeMapper;

    @MockBean
    TaggingService taggingService;

    @Test
    void test() {
        when(taggingService.tagging(any())).thenReturn(2);

        NodeDo nodeDo = new NodeDo();
        Node node = nodeMapper.toEntity(nodeDo);
    }

Embedded Redis

如果依赖了中间件或数据库,做单元测试时,有两种思路:

  • embedded service (基于内存)
  • TestsContainers(基于容器)

这里以 redis 为例,先探讨 embedded 的方式。需要添加如下测试依赖。

        
            it.ozimov
            embedded-redis
            0.7.2
            test
        

然后定义一个 RedisServer ,并用TestConfiguration 注解,仅作用于测试。

@TestConfiguration
public class TestRedisConfig {
    private final RedisServer redisServer = new RedisServer(6379);

    @PostConstruct
    public void postConstruct() {
        redisServer.start();
    }
    @PreDestroy
    public void preDestroy() {
        redisServer.stop();
    }
}

单元测试如下,classes 注意要添加上述类 TestRedisConfig

@Import(RedisConfig.class)
@SpringBootTest(classes = {
        ProductFieldServiceImpl.class,
        ProductFieldConverterImpl.class,
        LettuceConnectionFactory.class,
        TestRedisConfig.class
})
@ExtendWith(SpringExtension.class)
public class ProductFieldTest {

    @Autowired
    ProductFieldService productFieldService;

    @Test
    void getValue() {
        String value = productFieldService.getFormattedValue(ProductFieldValueQuery.of("WWW3037", "XZ_MF10"));
        System.out.println(value);
    }
}

Feign

对Feign接口进行单元测试时,需要 import 两个 configuration,因此可以抽一个基类出来,如下所示:

@ExtendWith(SpringExtension.class)
@Import({FeignAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class})
public class BaseFeignTest {

}

然后继承这个基类,并 enable 要测试的 client 即可。

@EnableFeignClients(clients = {ExampleFeign.class})
public class ProductFieldTest extends BaseFeignTest {

    @Autowired
    ExampleFeign feign;

    @Test
    void testFeign() {
        TagValuesDto result = feign.getProductFieldValue("WWW3037", "XZ_MF10").getData();
        System.out.println(result);
    }
}

DevOps

有了单元测试之后,我们希望每次编译部署都执行一次。此时只需将 maven -DskipTest=true 去掉,则会在每个发布的生命周期内执行单元测试。

一旦有测试用例不通过,就会阻断在自动化编译阶段。

对于屎山代码而言,可能会有些乱七八糟的test。此时如果我们只希望执行部分单元测试,要怎么做呢?

这个时候就需要在 pom.xmlbuild里面添加 surefire plugin,然后补充 excludes,即可跳过不希望执行的单元测试。示例如下。



    org.apache.maven.plugins
    maven-surefire-plugin
    2.22.2
    
        
        
        
        
        
        
        
        
            com/cmb/lr20/zxb/dialog/infrastructure/**/*.java
            com/cmb/lr20/zxb/dialog/infrastructure/*.java
            com/cmb/lr20/zxb/dialog/application/*.java
            com/cmb/lr20/zxb/dialog/external/**/*.java
            com/cmb/lr20/zxb/dialog/utils/*.java
            com/cmb/lr20/zxb/dialog/*ApplicationTest.java
        
    

你可能感兴趣的:(junit5mock)