我有一个测试,其中我编写了大部分所需的单元测试,但是有一个我想测试逻辑的前几位。只要方法被调用,我就不会在其余方法中发生什么,但是由于SUT由于缺少进一步的模拟而在NPE上失败,因此测试在我断言之前就失败了。
是否存在调用方法的 clean 方法,并忽略此后发生的所有异常?也许有某种在点击该方法并在此之后中止/通过测试的阻止行为?
我当时以为我可以写when(mock.methodIAmInterestedIn(any)).thenThrow(new RuntimeException("verified!"))
,然后简单地断言我得到了正确的异常(不过它将包装在另一个异常中)。这可能行得通,但是有点不干净:遮掩了我真正想要测试的内容。
@Test
public void should_load_using_filename_in_config() {
loader = new OrgUnitLoader(config, dbSupport.mockServices);
config = mock(TestConfiguration.class);
/* further mocking of the config needed if I am not to get an NPE */
when(dao.orgUnitsAreLoaded()).thenReturn(false);
// call the actual method
loader.loadOrgUnits();
verify(config, times(1)).getString(ORG_UNIT_DATA_FILE);
}
例如可以使用CountdownLatch
吗?
答案 0 :(得分:2)
我想测试逻辑的前几位。我不在乎其余方法
这似乎是您的受测代码无法通过单一责任模式。
您可能会考虑提取该方法的独立部分以将方法分离,甚至更好地分离为自己的对象。结果,您的当前方法将成为使用某些依赖项的组合方法,这些依赖项的逻辑很小,易于测试。
有两个明显的缺点:
- 然后,我需要打开SUT,将许多本应该私有的内部方法制作成具有程序包访问权限的方法,以便能够对其进行测试。 – oligofren
重点是,有必要独立于填充到当前方法中的实际业务逻辑来验证调度行为。 这告诉我,这种调度行为是它自己的责任,即与其他方法或方法分开。
在我看来,所有其他逻辑都属于其他类,而不仅是同一类中的单独方法。
这是相同抽象级别原则的结果,我们应该将其应用于类以及方法。实际上,这些新类至少将提供package private
访问其接口的信息。
- 我将非常紧密地绑定到SUT的内部,但是我想我已经在这样做了– – oligofren
这种“紧密绑定”可能仅存在于您的脑中,知道实际的实现。 您需要拆分代码进行测试的事实表明,代码没有您想象的那么严格。
我猜想所有单元测试决策(仅测试代码,开放等)都涉及某种实用主义。 –寡糖
关于单元测试,有一个非常简单的规则可以避免所有“务实的决定”:
UnitTest不测试 code ,UnitTest验证公共可观察到的行为,其中 public 表示:返回值和与依赖项通信。
没有“务实决定”的余地。唯一的决定是: CUT的预期行为是什么?
答案 1 :(得分:0)
由于您知道测试加载程序/配置不完整,因此您希望该方法在某些时候失败。在您的测试中考虑它:
@Test
public void should_load_using_filename_in_config() {
loader = new OrgUnitLoader(config, dbSupport.mockServices);
config = mock(TestConfiguration.class);
/* further mocking of the config needed if I am not to get an NPE */
when(dao.orgUnitsAreLoaded()).thenReturn(false);
try {
// call the actual method
loader.loadOrgUnits();
Assert.fail("Should fail as config is incomplete.");
} catch (NullPointerException e) {
verify(config, times(1)).getString(ORG_UNIT_DATA_FILE);
}
}
编辑(以下评论)
仅捕获预期的NPE会排除其他异常。如果在调用dao.orgUnitsAreLoaded()
之前抛出NPE将会失败。您会注意到的。
也许这不是很复杂,但是很容易理解( KISS )-甚至以后也可以理解。
@see Junit assert something after awaiting and handling an exception
答案 2 :(得分:0)
为什么不使用CompletableFuture
,则可以使用no-arg构造函数创建此类的实例来表示将来的某些结果,将其分发给使用者并在将来的某个时间完成使用完整的方法。使用者可以使用get方法来阻止当前线程,直到提供此结果为止。