Kre*_*sek 12 java junit mockito
Mockito在模拟client.getPrograms()哪些应该返回时报告未完成的存根错误SortedSet<Program>.有趣的是,它仅在使用Java 7时才这样做,而在使用Java 6时则不然.
以下是模拟时触发错误的代码client.getPrograms():
private void prepareScheduleChangePreconditions() {
Client client = mock(Client.class);
TimeTable tt = BuilderUtil.buildTable(AcceleratedScheduleTimeTable.Schedule.NORMAL, "08:00");
when(clientRepository.findByCode(anyString())).thenReturn(client);
//Error is reported for next line of code
when(client.getPrograms()).thenReturn(new TreeSet<Program>(Collections.singleton(program)));
when(event.getTimeTable()).thenReturn(tt);
}
Run Code Online (Sandbox Code Playgroud)
这是错误输出:
Tests in error:
testExampleScheduleChangeNotify1(com.example.service.impl.ExampleServiceImplTest):
Unfinished stubbing detected here:
-> at com.example.service.impl.ExampleServiceImplTest.prepareScheduleChangePreconditions(ExampleServiceImplTest.java:134)
E.g. thenReturn() may be missing.
Examples of correct stubbing:
when(mock.isOk()).thenReturn(true);
when(mock.isOk()).thenThrow(exception);
doThrow(exception).when(mock).someVoidMethod();
Hints:
1. missing thenReturn()
2. you are trying to stub a final method, you naughty developer!
Run Code Online (Sandbox Code Playgroud)
方法不是最终的.任何帮助或线索将不胜感激.
更新1
根据Mike B的请求,我设法将其分解为在Java 7中失败的更简单的测试用例.
@RunWith(MockitoJUnitRunner.class)
public class MockitoTest {
@Mock
Program program;
private void preparePreconditions() {
Client client = mock(Client.class);
when(client.getPrograms()).thenReturn(new TreeSet<Program>(Collections.singleton(program)));
}
public static class Client {
public SortedSet<Program> getPrograms() {
return new TreeSet<Program>();
}
}
public static class Program implements Comparable<Program> {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public int compareTo(Program program) {
return 0;
}
}
@Test
public void test() {
preparePreconditions();
}
}
Run Code Online (Sandbox Code Playgroud)
更新2
奇怪的是,如果我这样做,它的作用是:
TreeSet<Program> programs = new TreeSet<Program>();
programs.add(program);
when(client.getPrograms()).thenReturn(programs);
Run Code Online (Sandbox Code Playgroud)
我相信这里真正发生的不仅仅是单个when(...).then(...)语句中的一个模拟方法调用。
考虑以下示例:
when(program.getName()).thenReturn(String.valueOf(program.compareTo(null)));
Run Code Online (Sandbox Code Playgroud)
它返回与 You 相同的异常。这是因为在模拟上调用了两个方法:getName()和compareTo()在单个when(...).thenReturn(...)语句中。
同样在此页面(mockito 文档)中,您可以阅读:
默认情况下,对于所有返回值的方法,mock 返回 null、一个空集合或适当的原始/原始包装值(例如:0、false、...对于 int/Integer、boolean/Boolean、...)。
因此,mockito 必须有一些机制来检测对某个模拟对象的调用要做什么(返回)。
在您的示例中,第二次调用是通过new TreeSet<>(Collections.singleton(program))语句进行的,因为 TreeSet 构造函数正在使用compareTo()您的模拟方法。
似乎 TreeSet 的实现从 java 6 更改为 java 7。这就是它可以更早工作的原因。
这实际上并没有回答你的问题,但请记住模拟的主要指令:
实际上,这意味着模拟类(即不是接口)是一个闪烁的红色警告信号,表明您的设计有问题。
如果您无法控制所连接的代码(例如,它是第三方库或遗留软件),我喜欢将类包装在接口中并模拟它。作为奖励,这还允许您在其他代码中重命名命名不当的方法(和类)。从你的例子来看,客户端返回什么“程序”?是活动程序、运行程序的集合,什么?我们假设它是一组活动程序:
public interface Programs {
SortedSet<Program> active();
}
class SimpleClientWrapper implements Programs {
private final Client wrapped;
SimpleClientWrapper(Client c) { wrapped = c; }
public SortedSet<Program> active() { return wrapped.getPrograms(); }
}
Run Code Online (Sandbox Code Playgroud)
如果这感觉工作量太大(我承认有时这是矫枉过正),另一种可能性是,如果您想要模拟的方法是非最终的,则可以在测试中暂时覆盖它们:
Client client = new Client() {
@Override
public SortedSet<Program> getPrograms() {
return new TreeSet<Program>(Collections.singleton(program));
}
};
Run Code Online (Sandbox Code Playgroud)
我有时使用这种方法来覆盖错误处理程序等。