Tom*_*han 5 unit-testing mockito
我有一个非常复杂的方法,我想测试其行为(使用 Mockito 和 JUnit)。该方法将一个对象(我们称之为它的 type State)作为输入,并且应该考虑一些不同的状态变量来决定其输出。
作为示例,考虑以下规范(s是该类的模拟State):
s.varOne已设置,则返回其值。s.varTwo已设置,则返回该值。s.varThree已设置,则调用s.update(s.varThree)然后 return s.varOne,该值现在将具有一个值(即使在第 1 阶段没有)。为了正确测试案例 3,我想设置该s对象,以便s.varOne和s.varTwo都一开始就未设置,但如果(且仅当!) sut 调用s.update(s.varThree),然后s.varOne返回一些内容。
在 Mockito 中是否有设置此行为的好方法?
我考虑过为 建立一些返回值链s.varOne,然后验证调用的顺序是否与输出的顺序相对应(当然,sut 的返回值也是正确的),但这感觉很脏; 如果我随后更改方法以其他方式计算其返回值,即调用s.varOne不同次数但不更改其输出,那么即使功能相同,测试也会失败。
我理想的解决方案是一种可以为模拟对象添加一些“延迟”设置的方法,该设置在 sut 调用该s.update()方法时运行,但我无法找到实现该目标的方法。
您有几个选项可以在这里模拟状态更改,一个好的选项和一个更好的选项。正如上面tieTYT所指出的,最好的选择就是解开 的一般契约:可变以及拥有不是简单 setter 的自变异方法State真的有意义吗?State
好的选择(有时)是创建一个一次性子类\xe2\x80\x94,或者更好的是,创建一个接口实现\xe2\x80\x94of State。
@Test public void yourTest() {\n SystemUnderTest sut = createSystemUnderTest();\n State state = new State() {\n @Override public void update() {\n this.varOne = 42;\n }\n }\n // rest of your test\n}\nRun Code Online (Sandbox Code Playgroud)\n\n到那时,您可能根本不需要 Mockito。但请注意:如果 State 有副作用或难以实例化,这可能会变得有点棘手。您可以提取一个接口,这需要您将字段包装在 getter 中;您还可以将 State 设为一个命名抽象类,然后传递mock(MyAbstractState.class, CALLS_REAL_METHODS),但是当您考虑到没有初始化程序实际在该假实例上运行,因此字段全部为零或 null 时,这会变得特别棘手。如果这并不简单,就不要浪费时间将方钉强行插入圆孔中。
模拟的一种更常见的模式是使用自定义Answer,您可以在其中执行任意代码,但会牺牲类型安全性。这是一个示例,假设update是 void 并且varThree是整数:
@Test public void yourTest() {\n SystemUnderTest sut = createSystemUnderTest();\n final State s = Mockito.mock(State.class);\n doAnswer(new Answer<Void>() {\n @Override public Void answer(InvocationOnMock invocation) {\n int actualVarThree = (int) invocation.getArguments()[0];\n assertEquals(EXPECTED_VAR_THREE, actualVarThree);\n s.varOne = actualVarThree;\n return null;\n }\n }).when(s).update(anyInt());\n // rest of your test\n}\nRun Code Online (Sandbox Code Playgroud)\n\n请注意,参数数组是一个Object[],因此强制转换是必要的并且有点危险,但是当您的模拟方法被调用时,您可以同步进行各种断言和修改。
希望有帮助!
\n| 归档时间: |
|
| 查看次数: |
10640 次 |
| 最近记录: |