【问题标题】:Is the @SpringBootTest test class correct?@SpringBootTest 测试类是否正确?
【发布时间】:2019-01-17 09:21:27
【问题描述】:

这是单元测试的正确本质吗?我想我不明白我应该测试什么。 ConverterContext 是一个策略类

@SpringBootTest
@ExtendWith(SpringExtension.class)
class ConverterContextTest {

    @Autowired
    private final ConverterContext converterContext;
    @Autowired
    private final ConverterRegisterUserDto created;

    @Autowired
    ConverterContextTest(ConverterContext converterContext, ConverterRegisterUserDto created) {
        this.converterContext = converterContext;
        this.created = created;
    }

    @Test
    void converterContextGivesCorrectConverter(){
        ConverterRegisterUserDto returned = converterContext.getConverter(ConverterRegisterUserDto.class);
        assertEquals(returned, created);
    }

    @Test
    void converterContextGivesIncorrectConverter(){
        ConverterShowUserDto returned = converterContext.getConverter(ConverterShowUserDto.class);
        assertNotEquals(returned, created);
    }
}

【问题讨论】:

  • 你在测试什么?
  • 我正在测试 Converter Context 是否返回正确的对象

标签: java spring unit-testing spring-boot junit


【解决方案1】:

在单元测试中,您希望避免加载 Spring Boot 上下文。所以实例化自己ConverterContext.
如果ConverterContext 有一些需要隔离的依赖项,则可以模拟它们(请参阅 Mockito 库)。
此外,您不需要自动装配预期。
这将使您的测试更快地执行并且更易于阅读。
请注意,在您的代码中,ConverterContext 显示为工厂而不是策略。

关于你测试的逻辑,我认为不需要第二次测试。
您要检查的是工厂返回了设计返回的内容。
断言实际不等于愚蠢的预期是完全没有用的。这就像你必须维护的死代码...
实际上,就像您在第一个测试中断言 add(1,1) == 2 而在第二个测试中断言 add(2,1) != 2
为什么不断言所有愚蠢的预期都不相等? add(2,1)!= 4add(2,1)!= 5add(2,1)!= 6,我们可以继续很长一段时间......

我希望单元测试看起来像(我使用 JUnit 5 的方式来说明):

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

@ExtendWith(MockitoExtension.class)
class ConverterContextTest {

    ConverterContext converterContext;  

    @Mock
    FooDep fooDep;

    @Mock
    BarDep barDep;

    @BeforeEach // or @Before in JUnit 4
    void init{
        converterContext = new ConverterContext(fooDep, barDep);
    }

    @Test
    void converterContextGivesCorrectConverter(){
        // mock which is required
        /...
        assertEquals(new ConverterRegisterUserDto(), converterContext.getConverter(ConverterRegisterUserDto.class));
        // mock which is required
        /...
        assertEquals(new ConverterShowUserDto(), converterContext.getConverter(ConverterShowUserDto.class));
    }
}

【讨论】:

  • @Antoniossss 很多人忘记加载 Spring 容器不是免费的。
  • 看起来不错,但是当转换器在构造函数(依赖项)中有很多参数时该怎么办?如果是 ModelMapper 或 PasswordEncoder,我可以轻松创建实例,但如果是其他服务,我可能会遇到问题。所以你在这里写的这段代码是单元测试、集成测试还是其他?
  • 您应该模拟在测试中造成困难或不良耦合的依赖项。我更新说明。这是一个单元测试。
【解决方案2】:

单元测试的想法是测试尽可能小的代码。在大多数情况下,这意味着一个类及其方法的作用。至于要写多少测试,这真的取决于人。举个例子:

public class Point2D
{
    private int x, y;
    public Point2D() {this.x = 0; this,y = 0;}

    public int getX() {return x;}
    public int getY() {return y;}
}

class Point2DTest 
{  
    @Autowired
    private final Point2D p;

    @Test
    void getXReturnsZero()
    {
        int expected = 0;
        assertEquals(expected, p.getX());
    }

    @Test
    void getYReturnsZero()
    {
        int expected = 0;
        assertEquals(expected, p.getY());
    }

    @Test
    void getXDoesNotReturnZero()
    {
        int expected = 1;
        assertNotEquals(expected, p.getX());
    }

    @Test
    void getYDoesNotReturnZero()
    {
        int expected = 1;
        assertNotEquals(expected, p.getY());
    }

}

此测试可以保留前两种方法,但为了获得更多的测试覆盖率,人们可能会测试更多。我认为重要的是要注意详尽的测试(测试所有可能的结果)在现实生活场景中是不可能的,并且通常会定义一个截止点。

【讨论】:

    【解决方案3】:

    当您加载 Spring 上下文时,我倾向于将其更多地视为集成测试,而当您不加载 Spring 上下文并且您正在测试没有任何上下文的小方法的特定逻辑时,它更多地是单元测试。当您尝试在 Spring 上下文中测试仅实际依赖于其他注入 bean 的类时,您可以使用 Mockito 之类的框架来保持它们的单元测试并防止它们成为完整的集成测试。我希望这会有所帮助。

    【讨论】:

      猜你喜欢
      • 2019-09-15
      • 2020-03-21
      • 1970-01-01
      • 1970-01-01
      • 2019-01-23
      • 1970-01-01
      • 2017-07-24
      • 1970-01-01
      • 2013-03-08
      相关资源
      最近更新 更多