繁体   English   中英

如何测试使用其他方法的方法-Mockito,Java,Junit

[英]How to test method which uses other method - Mockito, java, junit

我想测试使用另一种方法吗? 我尝试使用Mockito做到这一点,如下所示:

编辑:完整方法

public String createUrlAddress(TypeOfInformation typeOfInformation, String icao) {
    switch (typeOfInformation) {
        case METAR:
            urlAddress = StaticValues.MAIN_URL_ADDRESS_FOR_METAR + icao;
            break;
        case TAF:
            urlAddress = StaticValues.MAIN_URL_ADDRESS_FOR_TAF + icao + StaticValues.TAF_4_HOURS_BEFORE_NOW;
            break;
        case CITY_PAIR_METAR:
            urlAddress = StaticValues.MAIN_URL_ADDRESS_FOR_CITY_PAIRS
                    + pc.getDepartureAndArrivalTime().get("departureTime") //get departure time from hashmap
                    + StaticValues.END_TIME_STRING
                    + pc.getDepartureAndArrivalTime().get("arrivalTime")
                    + StaticValues.STATION_STRING
                    + pc.getOriginIcao()
                    + ","
                    + pc.getDestinationIcao()
                    + StaticValues.MOST_RECENT_FOR_TYPED_STATIONS;
            System.out.println(urlAddress);
            break;
        case CITY_PAIR_TAFS:
            urlAddress = StaticValues.MAIN_URL_ADDRESS_FOR_CITY_PAIRS_TAFS
                    + pc.getDepartureAndArrivalTime().get("departureTime")
                    + StaticValues.END_TIME_STRING
                    + pc.getDepartureAndArrivalTime().get("arrivalTime")
                    + StaticValues.STATION_STRING
                    + pc.getOriginIcao()
                    + ",%20"
                    + pc.getDestinationIcao()
                    + StaticValues.MOST_RECENT_FOR_TYPED_STATIONS_TAFS;
            System.out.println(urlAddress);
            break;
        default:
            System.out.println("Wrong Type of informations");
    }
    return urlAddress;
}

测试:

@Test
    public void forGivenTypeOfInformationAndIcaoReturnUrl() {
        HashMap<String,Long> departureAndArrivalTimeTest = new HashMap<>();
        departureAndArrivalTimeTest.put("departureTime", 1499264449L);
        departureAndArrivalTimeTest.put("arrivalTime", 1499282449L);
        PageControllerForNearestCity pcSpy = Mockito.spy(pc);
        Mockito.when(pcSpy.getDepartureAndArrivalTime()).thenReturn(departureAndArrivalTimeTest);

        Mockito.when(pcSpy.getOriginIcao()).thenReturn("EPWA");
        Mockito.when(pcSpy.getDestinationIcao()).thenReturn("EDDF");

        assertThat(StaticValuesForTest.URL_ADDRESS_FOR_CITY_PAIR_METAR).isEqualTo(xmlParser.createUrlAddress(TypeOfInformation.CITY_PAIR_METAR, "EPGD")); }

在这种情况下,如何使用我的模拟? 是好的方法还是我必须以其他方式来做? 我想补充一点,我不会将这些变量作为此方法的参数添加。

PS我以为该方法只有一个可重复性,只创建一个字符串,对吗? 是否应该将其划分为另一个类似“服务”的内容?

谢谢你的支持

您的测试在实现细节中输入了太多内容。
您可以模拟自己的方法处理/逻辑。 因此,它使测试变得脆弱,我们可能会怀疑您的主张是什么。
此外,该测试阅读和维护都很复杂。

最后,与每种情况相关的处理都很重要。 这是您方法的主要逻辑:

case CITY_PAIR_METAR:

   urlAddress = StaticValues.MAIN_URL_ADDRESS_FOR_CITY_PAIRS
        + pc.getDepartureAndArrivalTime().get("departureTime") //get departure time from hashmap
        + StaticValues.END_TIME_STRING
        + pc.getDepartureAndArrivalTime().get("arrivalTime") //get arrival time from hashmap
        + StaticValues.STATION_STRING
        + pc.getOriginIcao()
        + ","
        + pc.getDestinationIcao()
        + StaticValues.MOST_RECENT_FOR_TYPED_STATIONS;
   System.out.println(urlAddress);

它应该像实际一样在没有嘲笑的情况下进行测试。

为此,您应该通过引入一个新类来分隔职责。
实际的类仅应具有控制器/调度程序角色,而新的类应根据情况使用公共方法执行逻辑。

这样,您要测试的类可以依赖于该类,并且可以直接模拟它们。

您的实际方法最终看起来像:

private AddressService addressService;

public String createUrlAddress(TypeOfInformation typeOfInformation, String icao) {
                switch (typeOfInformation) {

        (...)
                    case CITY_PAIR_METAR:
                        urlAddress = addressService.createUrl();
                        break;
         (...)
                    default:
                        System.out.println("Wrong Type of informations");
                }

               return urlAddress;
 }

@rafaelim在您回复后,我更新了我的测试类并将模拟注入到该类中,如下所示:

@Before
    public void setUp() throws Exception {
        departureAndArrivalTimeTest = new HashMap<>();
        xmlParser = new XmlParser();
        pc = new PageControllerForNearestCity();
        departureAndArrivalTimeTest.put("departureTime", 1499264449L); //second arg dep time in sec
        departureAndArrivalTimeTest.put("arrivalTime", 1499282449L); //second arg arr time in sec
    }

    @Test
    public void forGivenTypeOfInformationAndIcaoReturnUrl() {
        PageControllerForNearestCity pcSpy = Mockito.spy(pc);
        xmlParser.setPc(pcSpy);
        Mockito.when(pcSpy.getDepartureAndArrivalTime()).thenReturn(departureAndArrivalTimeTest);

        Mockito.when(pcSpy.getOriginIcao()).thenReturn("EPWA");
        Mockito.when(pcSpy.getDestinationIcao()).thenReturn("EDDF");


        assertThat(StaticValuesForTest.URL_ADDRESS_FOR_METAR).isEqualTo(xmlParser.createUrlAddress(TypeOfInformation.METAR, "EPGD"));
        assertThat(StaticValuesForTest.URL_ADDRESS_FOR_TAF).isEqualTo(xmlParser.createUrlAddress(TypeOfInformation.TAF, "EPGD"));
        assertThat(StaticValuesForTest.URL_ADDRESS_FOR_CITY_PAIR_METAR).isEqualTo(xmlParser.createUrlAddress(TypeOfInformation.CITY_PAIR_METAR, "EPGD"));
        assertThat(StaticValuesForTest.URL_ADDRESS_FOR_CITY_PAIR_TAF).isEqualTo(xmlParser.createUrlAddress(TypeOfInformation.CITY_PAIR_TAFS, "EPGD"));
    }

测试通过了,但是有点难以理解,我认为我必须使用“干净的代码”。

编辑:@davidxxx请看一下:

public class UrlAddressService {

    PageControllerForNearestCity pc = new PageControllerForNearestCity();

    public String createUrlForMetar() {

        String urlAddressForMetars = new StringBuilder()
                .append(StaticValues.MAIN_URL_ADDRESS_FOR_CITY_PAIRS)
                .append(pc.getDepartureAndArrivalTime().get("departureTime"))
                .append(StaticValues.END_TIME_STRING)
                .append(pc.getDepartureAndArrivalTime().get("arrivalTime"))
                .append(StaticValues.STATION_STRING)
                .append(pc.getOriginIcao())
                .append(",")
                .append(pc.getDestinationIcao())
                .append(StaticValues.MOST_RECENT_FOR_TYPED_STATIONS_METARS)
                .toString();

        return urlAddressForMetars;
    }

    public String createUrlForTaf() {

        String urlAddressForTafs = new StringBuilder()
                .append(StaticValues.MAIN_URL_ADDRESS_FOR_CITY_PAIRS_TAFS)
                .append(pc.getDepartureAndArrivalTime().get("departureTime"))
                .append(StaticValues.END_TIME_STRING)
                .append(pc.getDepartureAndArrivalTime().get("arrivalTime"))
                .append(StaticValues.STATION_STRING)
                .append(pc.getOriginIcao())
                .append(",%20")
                .append(pc.getDestinationIcao())
                .append(StaticValues.MOST_RECENT_FOR_TYPED_STATIONS_TAFS)
                .toString();

        return urlAddressForTafs;
    }
}

和createUrlAddress方法:

public String createUrlAddress(TypeOfInformation typeOfInformation, String icao) {
        switch (typeOfInformation) {

            case METAR:
                urlAddress = StaticValues.MAIN_URL_ADDRESS_FOR_METAR + icao;
                break;
            case TAF:
                urlAddress = StaticValues.MAIN_URL_ADDRESS_FOR_TAF + icao + StaticValues.TAF_4_HOURS_BEFORE_NOW;
                break;
            case CITY_PAIR_METAR:
                urlAddress = addressService.createUrlForMetar();
                break;
            case CITY_PAIR_TAFS:
                urlAddress = addressService.createUrlForTaf();
                break;
            default:
                System.out.println("Wrong Type of informations");
        }
        return urlAddress;
    }

您认为这是更好的方法吗? 在构建URL字符串期间,我无法减少代码,因为Tafs和Metars有3个不同的代码部分。 如果我的考试很差,你能告诉我最佳的测试方法吗?

我认为您的方向正确! 您在嘲笑代码的依赖关系,而该依赖关系正是PageControllerForNearestCity!

关于模拟的一种观察,您必须将其注入xmlParser中,如下所示:

@Test
public void forGivenTypeOfInformationAndIcaoReturnUrl() {
    // here you created the mock
    PageControllerForNearestCity pcSpy = Mockito.spy(pc);
    // I'll assume that xmlParser is the subject of your test
    // and that you're injecting the mock like code below 
    xmlParser.setPageController(pcSpy);

    // Configure the mock and then you do the assertion
    assertThat(...)
}

PS我以为该方法只有一个可重复性,只创建一个字符串,对吗? 是否应该将其划分为另一个类似“服务”的内容?

您的方法很好! 它确实做得很好,而且是从TypeOfInformation构建URL

我的建议是,在编写测试代码并使其通过之后,您可以重构代码! 您可以删除代码重复并使其更具可读性!

请记住:

“任何傻瓜都可以编写计算机可以理解的代码。 好的程序员编写人类可以理解的代码。”

马丁·福勒

好的编码!

编辑一些带有重构的代码示例

public String createUrlAddress(TypeOfInformation typeOfInformation, String icao) {
    String urlAddress;
    switch (typeOfInformation) {
        case METAR:
            urlAddress = StaticValues.MAIN_URL_ADDRESS_FOR_METAR + icao;
            break;
        case TAF:
            urlAddress = StaticValues.MAIN_URL_ADDRESS_FOR_TAF + icao + StaticValues.TAF_4_HOURS_BEFORE_NOW;
            break;
        case CITY_PAIR_METAR:
            // We delegate the build logic to pc because
            // all the information needed to build the url
            // is in the PageControllerForNearestCity class
            urlAddress = pc.urlAddressForCityPairMetar(); 
            break;
        case CITY_PAIR_TAFS:
            // Same
            urlAddress = pc.urlAddressForCityPairTafs();
            break;
        default:
            System.out.println("Wrong Type of informations");
    }
    return urlAddress;
}

class PageControllerForNearestCity {

    public String urlAddressForCityPairMetar() {
        return urlBasedOn(StaticValues.MAIN_URL_ADDRESS_FOR_CITY_PAIRSS, ",", StaticValues.MOST_RECENT_FOR_TYPED_STATIONS);
    }
    public String urlAddressForCityPairTafs() {
        return urlBasedOn(StaticValues.MAIN_URL_ADDRESS_FOR_CITY_PAIRS_TAFS, ",%20", StaticValues.MOST_RECENT_FOR_TYPED_STATIONS_TAFS);
    }
    // This method removes the duplication that I mentioned before
    private String urlBasedOn(String mainUrl, String separator, String endString) {
        return mainUrl
                + this.getDepartureAndArrivalTime().get("departureTime")
                + StaticValues.END_TIME_STRING
                + this.getDepartureAndArrivalTime().get("arrivalTime")
                + StaticValues.STATION_STRING
                + this.getOriginIcao()
                + separator
                + this.getDestinationIcao()
                + endString;
    }
}

请注意,在此重构之后, forGivenTypeOfInformationAndIcaoReturnUrl测试方法将变得更加简单。 但是您将必须为urlAddressForCityPairMetar ()和urlAddressForCityPairTafs ()创建测试。

暂无
暂无

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

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