Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/amazon-web-services/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何简化测试?_Java_Unit Testing_Junit_Mockito - Fatal编程技术网

Java 如何简化测试?

Java 如何简化测试?,java,unit-testing,junit,mockito,Java,Unit Testing,Junit,Mockito,我想测试我的方法IOConsoleWriterImpl.displayAllClientsInfo(列出客户端)是否打印数据 displayAllClientsInfo的结构大致如下: for (ClientEntity client : clients) { System.out.println(client.getName()); List<AccountEntity> accounts = client.getAccountEntities(); for

我想测试我的方法
IOConsoleWriterImpl.displayAllClientsInfo(列出客户端)
是否打印数据

displayAllClientsInfo
的结构大致如下:

for (ClientEntity client : clients) {
    System.out.println(client.getName());
    List<AccountEntity> accounts = client.getAccountEntities();
    for (AccountEntity account : accounts){
        System.out.println(account.getLogin());
    }
}
for(客户实体客户:客户){
System.out.println(client.getName());
List accounts=client.getAccountEntities();
for(会计实体账户:账户){
System.out.println(account.getLogin());
}
}
因此,据我所知,为了模拟两个foreach循环(使用Mockito),我需要模拟两个迭代器

有一个测试:

    @Test
    void isDisplayAllClientsInfoPrintData() {
        //Given
        List<ClientEntity> clients = mock(List.class);
        List<AccountEntity> accounts = mock(List.class);
        Iterator<ClientEntity> clientIterator = mock(Iterator.class);
        Iterator<AccountEntity> accountIterator = mock(Iterator.class);
        ClientEntity client = mock(ClientEntity.class);
        AccountEntity account = mock(AccountEntity.class);

        when(clientIterator.hasNext()).thenReturn(true, false);
        when(clientIterator.next()).thenReturn(client);
        when(clients.iterator()).thenReturn(clientIterator);

        when(accountIterator.hasNext()).thenReturn(true, false);
        when(accountIterator.next()).thenReturn(account);
        when(accounts.iterator()).thenReturn(accountIterator);

        when(clients.size()).thenReturn(1);
        when(client.getAccountEntities()).thenReturn(accounts);
        when(client.getId()).thenReturn(1L);
        when(client.getEmail()).thenReturn("client@example.com");
        when(client.getName()).thenReturn("John Smith");
        when(account.getId()).thenReturn(2L);
        when(account.getCreated()).thenReturn(LocalDateTime.of(2017,5,25,12,59));
        when(account.getLogin()).thenReturn("JSmith");
        when(account.getPassword()).thenReturn("zzwvp0d9");

        //When
        IOConsoleWriter io = new IOConsoleWriterImpl();
        io.displayAllClientsInfo(clients);

        //Then
        String output = outputStream.toString();
        assertAll(
                () -> assertTrue(output.contains(Long.toString(1))),
                () -> assertTrue(output.contains("client@example.com")),
                () -> assertTrue(output.contains("John Smith")),
                () -> assertTrue(output.contains(Long.toString(2))),
                () -> assertTrue(output.contains(LocalDateTime.of(2017,5,25,12,59).toString())),
                () -> assertTrue(output.contains("JSmith")),
                () -> assertTrue(output.contains("zzwvp0d9"))
        );
    }
@测试
void isDisplayAllClientsInfoPrintData(){
//给定
List clients=mock(List.class);
List accounts=mock(List.class);
迭代器clientIterator=mock(Iterator.class);
迭代器accountIterator=mock(Iterator.class);
ClientEntity client=mock(ClientEntity.class);
AccountEntity account=mock(AccountEntity.class);
when(clientIterator.hasNext())。然后返回(true,false);
when(clientIterator.next())。然后返回(client);
当(clients.iterator())。然后返回(clientIterator);
when(accountIterator.hasNext())。然后返回(true,false);
when(accountIterator.next())。然后返回(account);
when(accounts.iterator()).thenReturn(accountIterator);
当(clients.size())。然后返回(1);
当(client.getAccountEntities())。然后返回(accounts);
when(client.getId())。然后返回(1L);
当(client.getEmail())。然后返回(“client@example.com");
when(client.getName())。然后返回(“John Smith”);
when(account.getId())。然后返回(2L);
when(account.getCreated()).thenReturn(LocalDateTime.of(2017,5,25,12,59));
当(account.getLogin()).thenReturn(“JSmith”);
当(account.getPassword())。然后返回(“zzwvp0d9”);
//什么时候
IOConsoleWriter io=新IOConsoleWriterImpl();
io.displayAllClientsInfo(客户端);
//然后
字符串输出=outputStream.toString();
资产(
()->assertTrue(output.contains(Long.toString(1)),
()->assertTrue(output.contains()client@example.com")),
()->assertTrue(output.contains(“John Smith”),
()->assertTrue(output.contains(Long.toString(2)),
()->assertTrue(output.contains(LocalDateTime.of(2017,5,25,12,59).toString()),
()->assertTrue(output.contains(“JSmith”),
()->assertTrue(output.contains(“zzwvp0d9”))
);
}

我相信有一种很好的方法可以避免代码重复(我指的是测试的第二段和第三段)。或者我不必担心,一切都很好?

这一切看起来有点尴尬,所以我可以理解你关于如何简化它的想法

您可以只传入一个实际的列表,其中包含
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);
然后,在您的测试用例中,您可以将模拟的
编写器
注入
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"))
    );
公共类RecordingWriter实现Writer{
私有列表录制=新建ArrayList();
@凌驾
公共无效写入(字符串输出){
添加(输出);
}
公共布尔包含(传入字符串){
返回录制。包含(传入);
}
}
RecordingWriter=新的RecordingWriter();
IOConsoleWriter io=新IOConsoleWriterImpl(写入程序);
io.displayAllClientsInfo(客户端);
资产(
()->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
    集合并确定要打印的内容
  • 打印输出(包括标题和格式)
这使我认为提取
编写器
接口会带来一些好处:

  • 升级
    IOConsoleWriterImpl的SRP
  • 简化
    IOConsoleWriterImpl
  • 有助于简化对
    IOConsoleWriterImpl
    的测试,因为
    IOConsoleWriterTest
    可以只关注客户端的询问职责
  • 有助于简化“写作”行为的测试;您可以编写一个
    SystemOutWriterTest
    ,它只关注编写者的职责
然而,你已经做的是好的;它很好地覆盖了
IOConsoleWriterImpl.displayAllClientsInfo()
,尽管它非常详细,但仍然可读

总之,我建议传入一个实际的列表是最简单的更改,它(a)在功能上等同于您当前拥有的,并且(b)涉及较少的设置/更易于阅读。除此之外,我关于提取新接口背后的“编写”行为的建议将简化
IOConsoleWriterImpl
,并使您的测试更细粒度(每个测试用例可能更小,更容易推理),我认为这一更改将非常简单。当然,你对改变的渴望可能会有所不同;)还有好处呢
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"))
    );