对使用Mockito调用多个其他方法的方法进行单元测试



也许我的搜索完全失败了,但我找不到任何与如何为Java类/方法编写单元测试相关的文档或讨论,该类/方法反过来调用其他非私有方法。看起来,Mockito的立场是,如果必须使用间谍来测试一个需要模拟内部方法调用的方法,那么设计可能有问题(不是真正的OO)。我不确定这总是真的。但使用间谍似乎是实现这一目标的唯一途径。例如,为什么不能有一个"包装器"风格的方法,该方法反过来依赖于其他方法来实现基元功能,但还提供了功能、错误处理、日志记录或依赖其他方法结果的不同分支,等等。?

所以我的问题有两个:

  1. 拥有一个内部调用其他方法的方法是不是设计和实现都很糟糕
  2. 如果选择Mockito作为他们的嘲讽框架,那么为这种方法编写单元测试的最佳实践和/或方法是什么(假设这本身就是一个好主意)

这可能是一个困难的请求,但我更希望那些决定回答的人不要仅仅重新发布Mockito的措辞和/或对间谍的立场,因为我已经知道这种方法和意识形态。此外,我也使用过Powermockito。对我来说,这里的问题是Mockito开发了这个框架,其中必须创建额外的解决方案来支持这种需求。所以我想我想回答的问题是,如果间谍是"坏的",而Powermockito不可用,那么应该如何对调用其他非私有方法的方法进行单元测试?

一个方法在内部调用其他方法是不是设计和实现得很糟糕?

不是。但我想说,在这种情况下,调用其他方法的方法应该进行测试,就好像其他方法还没有单独测试一样。也就是说,它可以保护你不受公共方法在你没有注意到的情况下停止调用其他方法的情况的影响

是的,它(有时)会产生很多测试代码。我相信这就是重点:编写测试的痛苦是一个很好的线索,你可能想考虑将这些子方法提取到一个单独的类中。

如果我能接受这些测试,那么我认为还没有提取子方法。

如果选择Mockito作为他们的嘲讽框架,那么为这种方法编写单元测试的最佳实践和/或方法是什么(假设这本身就是一个好主意)?

我会这样做:

public class Blah {
public int publicMethod() {
return innerMethod();
}
int innerMethod() {
return 0;
}
}

public class BlahTest {
@Test
public void blah() throws Exception {
Blah spy = spy(new Blah());
doReturn(1).when(spy).innerMethod();
assertThat(spy.publicMethod()).isEqualTo(1);
}
}

对我来说,这个问题与衔接的概念密切相关。

我的答案是:

在一个类中有调用其他方法(私有)的方法(公共)是可以的,事实上,这通常是我认为的好代码。然而,需要注意的是,您的类仍然应该具有很强的凝聚力。对我来说,这意味着你的类的"状态"应该被很好地定义,你的类中的方法(思考行为)应该以可预测的方式改变你的类状态。

你要测试的是这种情况吗?如果没有,你可能在看一个类,而你应该看两个(或更多)。

您要测试的类的状态变量是什么?

你可能会发现,在考虑了这些类型的问题的答案后,你的代码变得更容易以你认为应该的方式进行测试

如果您真的需要(或想要)避免再次调用较低级别的方法,您可以将它们截断,而不是嘲笑它们。例如,如果方法A调用B和C,您可以这样做:

MyClass classUnderTest = new MyClass() {
@Override
public boolean B() {return true;}
@Override
public int C() {return 0;}
};
doOtherCommonSetUp(classUnderTest);
String result = classUnderTest.A("whatever");
assertEquals("whatIWant", result);

我在遗留代码中多次使用过这一点,在这些代码中,广泛的重构很容易导致软件版本的shipwright病:将难以测试的东西隔离到一个小方法中,然后将其截断。

但是,如果被调用的方法是无害的,并且不需要嘲笑,我就让它们再次被调用,而不用担心我覆盖了其中的每一条路径。

真正的问题应该是:

我真正想测试什么

实际上答案应该是:

我的对象响应外部更改的行为

也就是说,根据与对象交互的方式,您希望在单个测试中测试每个可能的单个场景。通过这种方式,你可以确保你的类根据你的期望做出反应,这取决于你提供测试的场景。

拥有一个内部调用其他方法的方法是不是设计和实现得很糟糕

不是真的,也不是真的!这些从公共成员调用的所谓私有方法就是助手方法。有辅助方法是完全正确的!

Helper方法可以帮助将一些更复杂的行为从类本身分解为更小的可重用代码。只有它知道它应该如何表现,并通过你班的公共成员相应地返回状态。

很少看到一个类带有helper方法,通常它们需要采用一种内部行为,而该类不应该从外部世界对此做出反应。

如果选择Mockito作为他们的嘲讽框架,那么为这种方法编写单元测试的最佳实践和/或方法是什么(假设这本身就是一个好主意)

在我看来,你没有测试这些方法。当公共成员在公共成员调用时通过您期望的对象状态进行测试时,就会对它们进行测试。例如,使用MVP模式,如果你想测试用户身份验证,就不应该测试每个私有方法,因为私有方法还可以从依赖于被测试对象的对象中调用其他公共方法,等等。相反,测试你的观点:

@TestFixture
public class TestView {
@Test
public void test() {
// arrange
string expected = "Invalid login or password";
string login = "SomeLogin";
string password = "SomePassword";
// act
viewUnderTest.Connect(login, password);
string actual = viewUnderTest.getErrorMessage;
// assert
assertEqual(expected, actual);
}
}

这个测试方法描述了单击connectButton后视图的预期行为。如果ErrorMessage属性不包含所需的值,这意味着您的视图或演示者的行为与预期不符。您可以检查演示者是否订阅了您视图的Connect事件,或者演示者是否设置了正确的错误消息等。

事实上,你永远不需要测试你的私有方法中发生的任何事情,因为你应该在调试时进行调整和更正,这反过来又会导致你同时测试你的内部方法的行为,但不应该为这些辅助方法专门编写任何特殊的测试方法。

相关内容

  • 没有找到相关文章

最新更新