【发布时间】:2017-11-11 02:58:53
【问题描述】:
我仍在思考 TDD 的部分内容。我有一个正在编写的新库,所以这似乎是一个尝试的好机会。
我在 TDD 上读到的内容宣传 100% 的代码覆盖率,但这似乎有点象牙塔,所以我将 JaCoco 配置为要求 90% 的代码覆盖率给我一些喘息的空间。
我开始编写加载 KeyStore 的代码。有很多样板代码和大量检查异常。所以从这里开始让我的生活更轻松。一切看起来都很好,我的测试通过了。但代码覆盖率仅为 49%。浏览代码,除了我称之为“不可能的异常”之外的所有内容都包括在内:
public void saveKey(Key key, String alias) {
KeyStore.SecretKeyEntry entry = new KeyStore.SecretKeyEntry(new SecretKeySpec(key.getMaterial(), "AES"));
try {
keyStore.setEntry(alias, entry, new KeyStore.PasswordProtection(password));
} catch (KeyStoreException e) {
throw new UnexpectedErrorException("Failed to save the key", e);
}
}
在这种特殊情况下,根据文档,如果 keyStore 尚未初始化,则会引发 KeyStoreException。我在进行防御性编码,并保证此时将初始化 keyStore。所以 KeyStoreException 不能被抛出。但这是一个检查异常,所以我必须处理它,所以我将它包装在自定义 RuntimeException 中。
问题是我无法在单元测试中触发此错误。事实上,我已尽我所能确保它不会发生。
在这种情况下,TDD 如何实现神话般的 100% 覆盖率?
我可以模拟 KeyStore,但 Mockito 的建议是“不要模拟你不拥有的类型”。所以我宁愿不要。此外,KeyStore 依赖于 Mockito 没有帮助的几个静态方法,我不想为简单的案例引入 PowerMock,而且我不相信在问题上投入更多的库是一个理想的解决方案。
所以:
- TDD 的 100% 代码覆盖率是神话吗?
- 是否有一种技术可以通过代码分析来识别此代码已被覆盖?
我目前预期的解决方案是将我配置的 90% 代码覆盖率限制降低到 40% 或 50%,直到我有更多类来提高我的总体平均覆盖率。但在我这样做之前,我还缺少什么吗?
【问题讨论】:
-
在单独的方法中粘贴以下行:
KeyStore.SecretKeyEntry entry = new KeyStore.SecretKeyEntry(new SecretKeySpec(key.getMaterial(), "AES"));并模拟该方法以抛出KeyStoreException -
这确实是一个公平的论点,但它把我们拖到了完全不同的地方:当你有一个依赖项时,你还应该对它进行集成测试,当合约 (API) 发生变化时,这些测试应该会中断。跨度>
-
顺便说一句,在您拥有的任何依赖项周围有一个(通常很薄的)包装器是一个好习惯,例如,当您决定切换到另一个库时,添加这一抽象层可以为您节省大量工作.第二个优势,是我们的例子——现在你在嘲笑你的包装器——而不是库!
-
这是一个很好的观点。这就是我正在考虑的包装类。但它可能不够薄,这给我带来了麻烦。 TDD 带来了更好的设计……去看看吧! :)
标签: java unit-testing tdd