繁体   English   中英

用许多模拟对象创建测试?

[英]Creating tests with many mock objects?

我对是否应该创建包含许多模拟对象的测试感到怀疑。

我最近读了我什么时候应该嘲笑? 我感到困惑。

让我们看一下我拥有的一种方法(只是为了说明问题)

@Override
protected void validate() throws WTException {
    Either<ImportError, RootFinderResult> rootPart = getDataValidator().getRootPart();
    if (rootPart.isLeft()) {
        addValidationMessage(ROOT_PART_NOT_FOUND);
    } else if (rootPart.isRight()) {
        getObjectsToValidate().forEach(Lambda.uncheckedBiConsumer((part, epmDocuments) -> {
            LocalizableMessage rootRevision = getRevision(part);

            Optional<EPMDocument> wrongRevisionEPM = epmDocuments.stream()
                    .filter(epmDocument -> !isSameRevision(rootRevision, epmDocument))
                    .findAny();

            wrongRevisionEPM.ifPresent(epmDocument -> addValidationMessage("blabla"));
        }));
    }
}

以下所有方法都需要与服务器建立连接才能起作用,否则它们将引发错误

getDataValidator().getRootPart();
getRevision(part)
!isSameRevision(rootRevision, epmDocument))

另外,我无法创建零件或epm文档的“真实”对象。 这也需要与服务器建立连接。


所以在这一点上,我真正要测试的实际上是这部分代码的逻辑

    Optional<EPMDocument> wrongRevisionEPM = epmDocuments.stream()
            .filter(epmDocument -> !isSameRevision(rootRevision, epmDocument))
            .findAny();

    wrongRevisionEPM.ifPresent(epmDocument -> addValidationMessage("blabla"));

但是要测试它,我需要模拟很多对象

@Spy
@InjectMocks
private SameRevision sameRevision;
@Mock
private WTPartRelatedObjectDataValidator wTPartRelatedObjectDataValidator;
@Mock
private ValidationEntry validationEntry;
@Mock
private WTPart rootPart1, rootPart2;
@Mock
private EPMDocument epmDocument1, epmDocument2, epmDocument3;
@Mock
private Either<ImportError, RootFinderResult> rootPart;
@Mock
private LocalizableMessage rootPartRevisionOne, rootPartRevisionTwo;

所以最后我可以测试逻辑:

@Test
@DisplayName("Should contain error message when part -> epms revisions are not the same")
void shoulHaveErrorMessagesWhenDifferentRevisions() throws Exception {
    doReturn(getMockObjectsToValidate()).when(sameRevision).getObjectsToValidate();

    doReturn(rootPart).when(liebherrWTPartRelatedObjectDataValidator).getRootPart();
    doReturn(false).when(rootPart).isLeft();
    doReturn(true).when(rootPart).isRight();

    doReturn(rootPartRevisionOne).when(sameRevision).getRevision(rootPart1);
    doReturn(rootPartRevisionTwo).when(sameRevision).getRevision(rootPart2);

    doReturn(true).when(sameRevision).isSameRevision(rootPartRevisionOne, epmDocument1);
    doReturn(false).when(sameRevision).isSameRevision(rootPartRevisionOne, epmDocument2);
    doReturn(true).when(sameRevision).isSameRevision(rootPartRevisionTwo, epmDocument3);

    validationEntry = sameRevision.call();

    assertEquals(1, validationEntry.getValidationMessageSet().size());
}

哪里

    doReturn(rootPart).when(liebherrWTPartRelatedObjectDataValidator).getRootPart();
    doReturn(false).when(rootPart).isLeft();
    doReturn(true).when(rootPart).isRight();

    doReturn(rootPartRevisionOne).when(sameRevision).getRevision(rootPart1);
    doReturn(rootPartRevisionTwo).when(sameRevision).getRevision(rootPart2);

可以移到@BeforeEach。


最后,我进行了测试,它可以正常工作。 它验证了我想要验证的内容,但是为了达到这一点,我不得不付出很多努力才能通过需要与服务器交互的整个API。

你们怎么看,创建这样的测试值得吗? 我想这是一个开放的话题,“因为许多尝试进入“测试世界”的新手都会遇到类似的问题,因此,请不要因为基于观点的判断而关闭该话题,并提供您对该话题的反馈。

您应该模拟将要测试的类所依赖的其他依赖关系,并设置所需的行为。 这需要完成以测试您的方法是否孤立,并且不依赖于thrirdparty类。您可以编写私有的void方法,该方法可以包含模拟行为,并在测试中使用它们;在@BeforeEach带注释的方法中,您可以模拟在所有测试中都相同的行为或在所有测试中模拟相同的模拟行为

在无效的方法中,您可以拥有一些间谍对象,如果像Mockito.verify()这样调用它们,则可以对其进行仿制。

你是对的。 模拟所有这些依赖关系是一项巨大的努力。 让我谈谈一些可能使事情变得更清楚的点:

  • 像对待投资一样对待编写测试:因此,是的,有时编写测试要比编写实际代码花费更多的精力。 但是,稍后引入错误时,您将感激不尽,并且测试可以抓住它。 拥有良好的测试可以使您有信心在修改代码时不会破坏任何内容,如果这样做,则测试会找到问题所在。 随着时间的流逝,它会得到回报。

  • 让您的考试集中在特定的课程上。 模拟其余部分:当模拟除被测类之外的所有内容时,可以确定发生问题时,该问题来自被测类,而不是其依赖项之一。 这使故障排除变得更加容易。

  • 编写新代码时要考虑可测试性:有时候,不可避免地要编写复杂的代码,很难测试。 但是,通常可以通过将所需的依赖项数量保持在最低限度并编写可测试的代码来避免这种情况。 例如,如果一个方法需要5或6个以上的依赖关系来完成其工作,则该方法可能做得太多,可能会分解。 可以在类级别,模块等上说同样的话。

是的,当您必须模拟这么多东西时,是相当多的投资时间。 我认为,如果您在测试某件产品时增加了一些价值,那值得进行测试,那么问题当然可能是您要花费多少时间。

在您的特定情况下,我将在不同的“层”上进行测试。

例如,方法:getDataValidator()。getRootPart(); getRevision(part)!isSameRevision(rootRevision,epmDocument))

可以对它们进行独立测试,并在您的情况下仅模拟其结果,这意味着您实际上并不关心那里的参数,您只关心在有特定返回值的情况下会发生什么。

因此,您可以在一层上真正地测试该功能,而在下一层上,您只需模拟所需的结果即可测试另一功能。

我希望现在更清楚...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM