java – 有没有更好的方法来测试以下方法,而没有模拟返回模拟?

假设以下设置:

interface Entity {}

interface Context { 
     Result add(Entity entity);
}

interface Result {
     Context newContext();
     SpecificResult specificResult();
}

class Runner {

    SpecificResult actOn(Entity entity, Context context) {
           return context.add(entity).specificResult();
    }
}

我想看到actOn方法只是将实体添加到上下文并返回specificResult.我正在测试这个的方式如下(使用Mockito)

@Test
public void testActOn() {
    Entity entity = mock(Entity.class);
    Context context = mock(Context.class);
    Result result = mock(Result.class);
    SpecificResult specificResult = mock(SpecificResult.class);
    when(context.add(entity)).thenReturn(result);
    when(result.specificResult()).thenReturn(specificResult);
    Assert.assertTrue(new Runner().actOn(entity,context) == specificResult);
}

然而,这似乎是可怕的白色盒子,嘲笑返回嘲笑.我做错了什么,有没有人有一个他们可以指出的好的“最佳实践”文本?

由于人们要求更多上下文,原始问题是DFS的抽象,其中Context收集图元素并计算结果,这些结果被整理并返回. actOn实际上就是叶子上的动作.

最佳答案
这取决于您希望测试代码的内容和数量.当你提到标签时,我想你在任何实际的生产代码之前编写了测试合同.

那么在你的合同中你想在actOn方法上测试什么:

>它返回给定Context和Entity的SpecificResult
> add(),specificResult()交互分别发生在Context和Entity上
> SpecificResult是Result返回的相同实例
>等

根据您要测试的内容,您将编写相应的测试.如果此部分代码不重要,您可能需要考虑放宽测试方法.如果这部分可以触发我们所知道的世界末日,则相反.

一般来说,白盒测试是脆弱的,通常是冗长的,不具有表现力,并且难以重构.但它们非常适合不应该改变很多的关键部分和新手.

在你的情况下有一个返回模拟的模拟看起来像一个白盒测试.但是如果你想在生产代码中确保这种行为,那就再好了.
Mockito可以帮助您使用深层存根.

Context context = mock(Context.class, RETURNS_DEEP_STUBS);
given(context.add(any(Entity.class)).specificResult()).willReturn(someSpecificResult);

但是不要习惯它,因为它通常被认为是不好的做法和测试气味.

其他评论:

>您的测试方法名称不够精确testActOn会告诉读者您正在测试的行为.通常,从业者用return_a_SpecificResult_given_both_a_Context_and_an_Entity这样的合同句子替换方法的名称,这显然更具可读性,并为从业者提供正在测试的范围.
>您正在使用Mockito.mock()语法在测试中创建模拟实例,如果您有多个测试,我建议您使用带有@Mock注释的MockitoJUnitRunner,这将使您的代码整理一下,并允许读者更好地了解这个特定测试中发生了什么.
>使用BDD(行为驱动开发)或AAA(安排行为断言)方法.

例如:

@Test public void invoke_add_then_specificResult_on_call_actOn() {
    // given
    ... prepare the stubs, the object values here

    // when
    ... call your production code

    // then
    ... assertions and verifications there
}

总而言之,正如Eric Evans告诉我Context是王道,你应该考虑到这个背景下的决定.但你真的应该尽可能地坚持最佳实践.

在这里和那里有很多关于测试的阅读,Martin Fowler在这个问题上有非常好的文章,詹姆斯卡尔编制了一份test anti-patterns的清单,还有许多关于使用好的模拟阅读(例如don’t mock types you don’t own mojo),Nat Pryce是合着者Growing Object Oriented Software Guided by Tests这是我认为必须阅读,加上你有谷歌;)

转载注明原文:java – 有没有更好的方法来测试以下方法,而没有模拟返回模拟? - 代码日志