我想测试我打印数据的方法DROP TABLE IF EXISTS schema.yourtable(even temporary tables #...)
。
IOConsoleWriterImpl.displayAllClientsInfo(List<ClientEntity> clients)
大致有以下结构:
displayAllClientsInfo
所以,据我所知,为了模拟两个foreach循环(使用Mockito),我需要模拟两个迭代器。
有测试:
for (ClientEntity client : clients) {
System.out.println(client.getName());
List<AccountEntity> accounts = client.getAccountEntities();
for (AccountEntity account : accounts){
System.out.println(account.getLogin());
}
}
我相信有一种避免代码重复的好方法(我的意思是测试的第二和第三段)。或者我不应该担心,一切都很好?
答案 0 :(得分:2)
这一切看起来有点尴尬,所以我能理解你对如何简化它的想法。
您只需传入{strong>实际 ClientInfo
个实例列表,而不是模拟实例。例如:
List<ClientInfo> clientInfos = new ArrayList<>();
clients.add(new ClientInfo(1L, "client@example.com", "John Smith",
Arrays.asList(
new Account(2L, LocalDateTime.of(2017,5,25,12,59), "JSmith", "zzwvp0d9"))
)
);
io.displayAllClientsInfo(clients);
但这似乎是显而易见的,所以也许有一些理由说明你还没有这样做(可能构建这些类有点笨拙或过于冗长)。
或者,您可以通过使代码更加适合测试来支持“测试设置”的尴尬。例如,您可以将IOConsoleWriterImpl
中的“写入”责任提取到注入IOConsoleWriterImpl
的界面中。像这样:
// extract from IOConsoleWriterImpl
public IOConsoleWriterImpl(Writer writer) {
this.writer = writer;
}
public void displayAllClientsInfo(ClientEntity clients) {
for (ClientEntity client : clients) {
System.out.println(client.getName());
List<AccountEntity> accounts = client.getAccountEntities();
for (AccountEntity account : accounts){
writer.write(account.getLogin());
}
}
}
// a new interface to extract the 'writing' behaviour out of IOConsoleWriterImpl
public interface Writer {
void write(String output);
}
// a sysout implementation of the Writer interface
public class SystemOutWriter implements Writer {
@Override
public void write(String output) {
System.out.println(output);
}
}
然后在您的测试用例中,您可以将一个模拟的Writer
注入IOConsoleWriter
,并验证是否已按预期状态调用它。
Writer writer = Mockito.mock(Writer.class);
IOConsoleWriter io = new IOConsoleWriterImpl(writer);
io.displayAllClientsInfo(clients);
Mockito.verify(writer).write(...);
类似地,您可以提供Writer
的存根实现,该实现记录它的内容,然后断言此存根的内容。例如:
public class RecordingWriter implements Writer {
private List<String> recordings = new ArrayList<>();
@Override
public void write(String output) {
recordings.add(output);
}
public boolean contains(String incoming) {
return recordings.contains(incoming);
}
}
RecordingWriter writer = new RecordingWriter();
IOConsoleWriter io = new IOConsoleWriterImpl(writer);
io.displayAllClientsInfo(clients);
assertAll(
() -> assertTrue(writer.contains(Long.toString(1))),
() -> assertTrue(writer.contains("client@example.com")),
() -> assertTrue(writer.contains("John Smith")),
() -> assertTrue(writer.contains(Long.toString(2))),
() -> assertTrue(writer.contains(LocalDateTime.of(2017,5,25,12,59).toString())),
() -> assertTrue(writer.contains("JSmith")),
() -> assertTrue(writer.contains("zzwvp0d9"))
);
更新1 :根据您的评论以及您在此处提供给实际课程的链接。
看起来IOConsoleWriterImpl.displayAllClientsInfo()
有两个职责:
ClientInfo
的集合并制定要打印的内容这让我觉得提取Writer
界面会带来一些好处:
IOConsoleWriterImpl
IOConsoleWriterImpl
IOConsoleWriterImpl
的简单测试,因为IOConsoleWriterTest
可以专注于客户端审讯责任 SystemOutWriterTest
专注于只是作家的责任 然而,你已经做过的事情还可以。它提供了IOConsoleWriterImpl.displayAllClientsInfo()
的良好覆盖率,虽然它非常详细,但它仍然可读。
总之,我建议传入一个实际的List是最简单的变化,它是(a)功能上与你现在拥有的相同,并且(b)涉及更少的设置/更容易阅读。除此之外,我关于提取新界面背后的“写入”行为的建议将简化IOConsoleWriterImpl
并使您的测试更精细(每个测试用例可能更小,更容易推理)并且此更改将 - 我认为 - 制作非常简单。当然,你对变革的兴趣可能会有所不同;)这里的好处并不足以引起这种变化。