当前位置: 首页 > 工具软件 > TestableMock > 使用案例 >

单元测试框架TestableMock快速入门(四):Mock的生效范围

公孙高轩
2023-12-01

目录

一、概述

二、使用案例


一、概述

@MockMethod@MockConstructor注解上都有一个scope参数,其可选值有两种:

  • MockScope.GLOBAL:该Mock方法将全局生效;
  • MockScope.ASSOCIATED:该Mock方法仅对Mock容器关联测试类中的测试用例生效;

对于常规项目而言,单元测试里需要被Mock的调用都是由于其中包含了不需要或不便于测试的逻辑,譬如“依赖外部系统”、“包含随机结果”、“执行非常耗时”等等,这类调用在整个单元测试的生命周期里都应该被Mock方法置换,不论调用的发起者是谁。因此TestableMock默认所有Mock方法都是全局生效的,即scope默认值为MockScope.GLOBAL

二、使用案例

举例来说,CookerServiceSellerService是两个需要被测试的类,假设CookerService的代码里的hireXxx()cookXxx()方法都需要依赖外部系统。因此在进行单元测试时,开发者在CookerService关联的Mock容器里使用@MockMethod注解定义了这些调用的替代方法。

此时,若该Mock方法的scope值为MockScope.GLOBAL,则不论是在SellerServiceTest测试类还是在CookerServiceTest测试类的测试用例,只要直接或间接的执行到这行调用,都会被置换为调用Mock方法。若该Mock方法的scope值为MockScope.ASSOCIATED,则Mock只对CookerServiceTest类中的测试用例生效,而SellerServiceTest类中的测试用例在运行过程中执行到了CookerService类的相关代码,将会执行原本的调用。

 【a】编写CookerService被测试类

package com.wsh.testable.mock.testablemockdemo;

/**
 * 目标类,此类中的一些调用将会被Mock掉
 */
public class CookerService {

    private static String hireSandwichCooker() {
        return "Real-Sandwich-Cooker";
    }

    private static String hireHamburgerCooker() {
        return "Real-Hamburger-Cooker";
    }

    private String cookSandwich() {
        return "Real-Sandwich";
    }

    private String cookHamburger() {
        return "Real-Hamburger";
    }

    public String prepareSandwich() {
        return hireSandwichCooker() + " & " + cookSandwich();
    }

    public String prepareHamburger() {
        return hireHamburgerCooker() + " & " + cookHamburger();
    }

}

【b】编写SellerService被测试类

package com.wsh.testable.mock.testablemockdemo;

/**
 * 被测类,会访问`CookerService`里的方法
 */
public class SellerService {

    private CookerService cookerService = new CookerService();

    public String sellSandwich() {
        return cookerService.prepareSandwich();
    }

    public String sellHamburger() {
        return cookerService.prepareHamburger();
    }
}

【c】编写针对CookerService被测试类的Mock容器CookerServiceMock

package com.wsh.testable.mock.testablemockdemo;

import com.alibaba.testable.core.annotation.MockMethod;
import com.alibaba.testable.core.model.MockScope;

/**
 * 此Mock容器类针对CookerService被测试类
 */
class CookerServiceMock {

    /**
     * 默认scope为MockScope.GLOBAL,全局有效,所以CookerService、SellerService只要
     * 有外部调用到此Mock方法,都将执行Mock之后的方法
     */
    @MockMethod(targetClass = CookerService.class)
    public static String hireSandwichCooker() {
        return "Fake-Sandwich-Cooker";
    }

    /**
     * 作用域为MockScope.ASSOCIATED, 则Mock只对CookerServiceTest类中的测试用例生效,而SellerServiceTest类中的测试用例在
     * 运行过程中执行到了CookerService类的相关代码,将会执行原本的调用。
     */
    @MockMethod(targetClass = CookerService.class, scope = MockScope.ASSOCIATED)
    public static String hireHamburgerCooker() {
        return "Fake-Hamburger-Cooker";
    }

    @MockMethod(targetClass = CookerService.class)
    private String cookSandwich() {
        return "Faked-Sandwich";
    }

    @MockMethod(targetClass = CookerService.class, scope = MockScope.ASSOCIATED)
    private String cookHamburger() {
        return "Faked-Hamburger";
    }
}

可以看到,在Mock容器类中,我们在MockMethod注解上标注了此Mock方法的作用域。如果标注了MockScope.ASSOCIATED,Mock只对CookerServiceTest类中的测试用例生效,而 SellerServiceTest类中的测试用例在运行过程中执行到了CookerService类的相关代码,将会执行原本的调用。

【d】编写CookerServiceTest测试类

package com.wsh.testable.mock.testablemockdemo;

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;

class CookerServiceTest {

    private CookerService cookerService = new CookerService();

    @Test
    void should_cooker_sandwich() {
        assertEquals("Fake-Sandwich-Cooker & Faked-Sandwich",
                cookerService.prepareSandwich());
    }

    /**
     * 因为作用域为:MockScope.ASSOCIATED,Mock只对CookerServiceTest类中的测试用例生效,而
     * SellerServiceTest类中的测试用例在运行过程中执行到了CookerService类的相关代码,将会执行原本的调用。
     */
    @Test
    void should_cooker_hamburger() {
        assertEquals("Fake-Hamburger-Cooker & Faked-Hamburger",
                cookerService.prepareHamburger());
    }

}

【e】编写SellerServiceTest测试类

package com.wsh.testable.mock.testablemockdemo;

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;

class SellerServiceTest {

    private SellerService sellerService = new SellerService();

    @Test
    void should_sell_sandwich() {
        assertEquals("Fake-Sandwich-Cooker & Faked-Sandwich", sellerService.sellSandwich());
    }

    /**
     * 因为作用域为:MockScope.ASSOCIATED,Mock只对CookerServiceTest类中的测试用例生效,而
     * SellerServiceTest类中的测试用例在运行过程中执行到了CookerService类的相关代码,将会执行原本的调用。
     * <p>
     * 原本调用就是分别返回: "Real-Hamburger-Cooker"、"Real-Hamburger"。
     */
    @Test
    void should_sell_hamburger() {
        assertEquals("Real-Hamburger-Cooker & Real-Hamburger", sellerService.sellHamburger());
    }

}

 类似资料: