繁体   English   中英

这是对这种方法进行单元测试的好方法吗?

[英]Is it good way to unit test this method?

我需要使用Junit / Mockito测试此方法。 实际上,我无法使用Mockito正确编写测试,因此我使用了自己的输入来代替模拟扫描仪。 我不知道我是否做对了。 (有人知道如何使用Mockito吗?)

这是我要测试的方法:

public RentingACar rentACar(Scanner input) {
    RentingACar rentingACar = new RentingACar();

    System.out.print("Brand: ");
    rentingACar.setBrand(input.next());
    System.out.print("Name: ");
    rentingACar.setName(input.next());
    System.out.print("Surname: ");
    rentingACar.setSurname(input.next());
    System.out.print("Rent Date: ");
    rentingACar.setRentDate(input.next());
    System.out.print("Client number: ");
    rentingACar.setClientNumber(input.nextInt());

    return rentingACar;
}

这是我的测试:

@Test
void rentACar() {
    Scanner scanner = new Scanner("Mazda\nPeter\nParker\n20.02\n1234");
    ClientDataGetter clientDataGetter = new ClientDataGetter();

    RentingACar rentingACar = clientDataGetter.rentACar(scanner);

    assertNotNull(rentingACar);

    assertEquals("Mazda", rentingACar.getBrand());
    assertEquals("Peter", rentingACar.getName());
    assertEquals("Parker", rentingACar.getSurname());
    assertEquals("20.02", rentingACar.getRentDate());
    assertEquals(1234, rentingACar.getClientNumber());
}

有什么意义吗?

为什么在不需要Mockito时会使用Mockito,地狱,使用Mockito编写代码比没有Mockito的问题更多? Mockito是完全不得已的选择(例如,模拟数据库或外部服务),即使这样,是否应该使用它还是值得怀疑的(而不是仅仅编写自己的FakeDatabaseFakeExternalService )。 这里绝对不需要,一个被嘲笑的Scanner还能提供什么帮助?

我说您的方法很好,即使您要测试的代码仍有很多不足之处。 因为这个问题是关于测试的,所以我不会谈论代码本身。

您仅测试了所谓的“快乐路径”,这意味着输出完美且一切正常的情况。

您还需要做的是测试边缘情况(输入最大/最小时,例如L.MIN_VALUE / 0 / Long.MAX_VALUE的数字,字符串的长度为0等),例如使用空/一个字母名称,客户编号以0开头。

毕竟,您需要测试输入是否完全错误:没有\\n符号,没有日期应为日期的等等,这里有很多可能性。 您可能会发现代码还不够,您将不得不对其进行更改(也许添加一些输入验证)。 这就是为什么最好从测试(测试驱动的开发)开始的原因,您可以在编写代码之前先看到必须做的验证,然后您将为此做好准备。 这是简单的情况,但是向已经存在的代码中添加重要的功能并不总是那么容易,而且如果某人已经使用了该代码,甚至可能会有风险。 我见过很多情况,当某人需要进行这样的修改时,但是如果没有巨大的重构是不可能的,所以这就是他们所做的(请不要做):

if(mySpecialCase) {
  // all the logic
} else {
  // all the logic, almost identical to the logic above
}

编辑:回复您的评论- Why is it bad practice to make if conditions?

我不仅在这里讨论if条件。 我说的是两个潜在的重复代码if分支,他们将最有可能有非常相似的代码。 想象一下,你有其他的变化使,你得再添if这两个分支,它成为一个烂摊子。

If条件也不应该被过度使用,尤其是当条件归结为许多不同的分支时。 仅通过查看代码就很难调试,测试和查看正在发生的事情。 一定要有人(或您)通过查看并分析代码来了解代码的作用,这一点非常重要。 解决这个问题通常并不容易,需要使用一些设计模式 (例如decorator) ,有时甚至是一个简单的开关也可以提供很多帮助。

这就是我使用Mockito编写测试的方式。

import org.junit.Test;
import java.util.Scanner;

import static org.mockito.Mockito.*;

public class ClientDataGetterTest {

    ClientDataGetter clientDataGetter = new ClientDataGetter();

    @Test
    public void testRentACar() {
       // define input data (test Scanner object)
        Scanner scanner = new Scanner("Mazda\nPeter\nParker\n20.02\n1234");

        // call you method
        RentingACar rentACar = spy(new RentingACar());
        clientDataGetter.rentACar(rentACar, scanner);

        // Verify that the methods were called with exact parameter values and exactly one time each
        verify(rentACar, times(1)).setBrand("Mazda");
        verify(rentACar, times(1)).setName("Peter");
        verify(rentACar, times(1)).setSurname("Parker");
        verify(rentACar, times(1)).setRentDate("20.02");
        verify(rentACar, times(1)).setClientNumber(1234);

        // Old code
/*
        //check the results
        assertEquals("Mazda", rentingACar.getBrand());
        assertEquals("Peter", rentingACar.getName());
        assertEquals("Parker", rentingACar.getSurname());
        assertEquals("20.02", rentingACar.getRentDate());
        assertEquals(1234, rentingACar.getClientNumber());
*/
    }

Mockito正在确保您的二传手被叫到。

我个人认为,如果您的RentingACar看起来像一个简单的POJO,那么就不需要像我一样模拟它了,那么您的方法很好。

潜在的更改无效。

您可以通过如下定义Mockito for Scanner://为扫描器定义模拟

Scanner scanner = mock(Scanner.class);
when(scanner.next()).thenReturn("Mazda","Peter","Parker","20.02","1234");

但是嘲笑不能嘲笑最后的课程。 标准的java.util.Scanner是最终类。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM