4

我必须处理一个没有测试的遗留应用程序。所以在我开始重构之前,我想确保一切正常。

现在想象以下情况:

public SomeObject doSomething(final OtherObject x, final String something) {
    if(x == null) throw new RuntimeException("x may not be null!");
    ...
}

现在我想测试那个空检查,以确保它有效并且一旦我重构就不会丢失它。

所以我做了这个

@Test(expected = RuntimeException.class)
public void ifOtherObjectIsNullExpectRuntimeException() {
    myTestObject.doSomething(null, "testString");
}

现在,这当然有效。

但我想传入一个随机字符串,而不是“testString”。

所以我尝试了:

@Test(expected = RuntimeException.class)
public void ifOtherObjectIsNullExpectRuntimeException() {
    myTestObject.doSomething(null, Mockito.anyString());
}

但这是不允许的。,正如我得到的

org.mockito.exceptions.misusing.InvalidUseOfMatchersException: ...您不能在验证或存根之外使用参数匹配器

我确实理解这个的含义,但我想知道我是否仍然可以在不参数化我的测试等的情况下做我想做的事情。我可能使用的唯一库是 Junit、AssertJ、Mockito 和 Powermock。

有任何想法吗?

4

4 回答 4

4

测试应该是确定性的。在测试中使用随机值使得在调试失败的测试时难以重现行为。我建议您只String为测试创建一个常量,例如"abcdefg".

于 2016-09-09T19:36:05.293 回答
3

好吧,就像 Mockito 试图通过那个异常告诉你一样,这并不是你真正使用anyString. 此类方法仅供模拟使用。

那么,为什么不尝试使用实际的随机字符串进行测试呢?在这种情况下,我个人最喜欢:. 这几乎总是会生成一个以前从未用于测试的全新字符串。java.util.UUID.randomUUID().toString()

我还想补充一点,如果您正在为您的SomeObject班级编写测试,您应该避免嘲笑SomeObject的行为。从您的示例中,您并没有完全这样做,但看起来您可能正在走那条路。模拟您尝试测试的实现的依赖关系,而不是实现本身!这个非常重要; 否则你实际上并没有测试任何东西。

于 2016-09-09T20:02:04.323 回答
2

你在这里混淆了概念。

所有像anyString()这样的“模拟”助手都是在配置模拟对象时使用的。

但是当你检查你的测试代码时:

@Test(expected = RuntimeException.class)
public void ifOtherObjectIsNullExpectRuntimeException() {
  myTestObject.doSomething(null, "testString");
}

你会发现:这个测试绝对不涉及任何嘲弄。你根本不能在那个地方使用那些 Mockito 调用;因为那个地方“没有Mockito”。

只是为了记录 - 无论如何都不需要在这里过火。您的逻辑在这里非常清楚:当第一个参数为空时,您会抛出该异常。因此,作为第二个参数出现的内容实际上并不重要。因此,思考一个小时如何使用任何第二个参数来测试 null 是,好吧,在我看来:浪费你的时间。

最后提示:有java.lang.Objects 并且该类对 null 有很好的检查,所以我的生产代码看起来像

public SomeObject doSomething(final OtherObject x, final String something) {
  Objects.requireNonNull(otherObject, "otherObject must not be null");
  Objects.requireNonNull(something, "something must not be null");

唯一的区别:需要...抛出 NullPointerExceptions

final finally:有人建议将final放在每个参数上;但我不会那样做。在 99% 的情况下,它没有增加任何价值。这只是意味着你有更多的代码要阅读;没有好的理由。但这是风格问题。

编辑关于进行测试以检查未来可能发生的变化的评论:你不应该这样做:

  1. 在某种程度上,如何验证您的输入是一个实现细节。您不测试实施细节。换句话说:
  2. 您的方法有一个特定的合同(例如,您通过编写一个说明“在空输入上抛出 NPE”的 javadoc 来非正式地指定该合同)。您的测试应该准确地验证当前的合同。合同是:如果第一个参数为空,则抛出。

也许是另一种观点;因为我仍然认为你在这里浪费时间!您应该确保所有界面都清晰、易于理解且易于使用。它们允许您的代码的用户轻松地做正确的事情;并防止他做错事。这就是您应该关注的 - 整个界面的质量!因此,不必担心如何为潜在的未来变化编写测试;只要确保你的代码库是整体一致的。

于 2016-09-10T04:33:48.757 回答
0

好吧,我对 mockito 了解不多,但您始终可以创建自己的随机字符串生成器。也许这可以工作,你可以在其中修改更多类型的输入

于 2016-09-09T19:34:40.643 回答