使用已测试方法的单元测试方法

Unit testing method that uses already tested method

提问人:Szyszka947 提问时间:5/14/2023 最后编辑:MureinikSzyszka947 更新时间:6/5/2023 访问量:46

问:

假设我们有类和类。用于验证传入请求。HandlerValidatorHandlerValidator

该类经过单元测试,是否返回适当的错误等。Validator

稍后,我们想为 .已经有单元测试了,那么测试会是什么样子呢?HandlerValidatorHandler

我们是否会编写与是否返回适当的错误(从类中检索)相同的测试?这对我来说没有意义。ValidatorHandlerValidator

那么,在这种情况下,类的单元测试会是什么样子呢?Handler

单元测试 java mockito junit

评论

1赞 Eyal Gerber 5/14/2023
目前尚不清楚 Handler 和 Validator 之间是什么关系?例如,Handler 是从 Validator 派生的还是其他东西?请更具体。
0赞 Szyszka947 5/14/2023
我添加了这些类之间的关系

答:

2赞 Mureinik 5/14/2023 #1

不应在 单元测试中重新测试 的逻辑。ValidatorHandler

单元(与组件、集成或端到端测试相反)的概念是隔离您正在测试的最小单元(通常是类)的逻辑。

教科书上的解决方案是嘲笑,然后测试它们是否对可能具有的不同行为做出适当的反应。ValidatorHandlerValidator

你没有用任何编程语言来标记问题,但任何半体面的语言都应该有一些库来允许嘲笑。例如,这是我在 中使用 的方法:

// Imports snipped for brevity's sake
@ExtendWith(MockitoExtension.class)
public class HandlerTest {
    // Create a mock Validator
    @Mock
    private Validator validator;

    private Handler handler;

    // Set up the handler being tested with said validator
    @BeforeEach
    public void setUp() {
        handler = new Handler(validator);
    }

    @Test
    void handlePassedValidation() {
        // Mock the validator with a "passing" validation
        when(validator.isValid()).thenReturn(true);
      
        handler.handle();

        // Assert the handler did what it should when the validation passed
    }

    @Test
    void handleFailedValidation() {
        // Mock the validator with a "failing" validation
        when(validator.isValid()).thenReturn(false);
      
        handler.handle();

        // Assert the handler did what it should when the validation failed
    }
}
3赞 Mike Nakis 5/14/2023 #2

穆雷尼克在他的回答中提出的嘲讽解决方案确实是教科书式的解决方案。这是地球上大多数人所做的事情,也是大多数人认为正常的事情。在我看来,这也是被严重误导的,我不是唯一一个这样想的人:

  • 在视频 Thoughtworks - TW Hangouts: Is TDD dead ?(youtube) at 21':10'' Kent Beck维基百科)说:“我个人的做法是我几乎什么都不嘲笑。
  • 在同一段视频中,在23分56秒,马丁·福勒维基百科)补充说:“我和肯特在一起,我几乎从不使用模拟。
  • 在《xUnit Test Patterns: Refactoring Test Code》(xunitpatterns.com)一书的“脆弱测试”一节中,作者 Gerard Meszaros 指出“大量使用模拟对象会导致过度耦合测试”。
  • 在他的演讲中,TDD到底哪里出了问题?InfoQ,YouTube) 在 49':32'' 伊恩·库珀(Ian Cooper)说:“我非常反对嘲笑,因为它们被过度指定了。

如果你想了解更多关于为什么模拟是一个坏主意的信息,请参阅我的博客文章:michael.gr - 关于模拟对象和模拟

处理此问题的更好方法是我称之为增量集成测试的方法。这意味着永远不要模拟任何东西,总是在你的测试中集成实际的依赖关系,(或伪造的,但从不模拟),并简单地安排测试的执行顺序,以便首先测试最依赖的类,然后测试依赖它们的类。这样,对 的测试就可以利用 并理所当然地认为它有效,因为对 的测试已经运行,并且已经通过。HandlerValidatorValidator

不幸的是,测试框架对按特定顺序执行测试的支持很少(如果有的话)。我已经为基于 maven 的 java 项目编写了一个工具来解决这个问题,但你可能没有使用 java 或 maven,或者你可能不愿意使用某个人构建的一些奇怪的工具。幸运的是,有一个手动解决方法:测试框架倾向于按字母顺序执行测试,因此您仍然可以通过命名测试的方式来强制执行测试的执行顺序,使其字母顺序与执行顺序一致。例如,可以将测试命名为 、 等,以便 的测试始终在 的 测试之前运行。您可能还必须以类似方式命名包和/或命名空间。T01_ValidatorTestT02_HandlerTestValidatorHandler

有关增量集成测试的更多信息,请参阅我的博客:michael.gr - 增量集成测试

评论

1赞 Eyal Gerber 6/4/2023
这是一个非常翔实的答案。谢谢