testable-mock/docs/zh-cn/doc/use-mock-with.md
2021-02-20 09:03:44 +08:00

3.6 KiB
Raw Blame History

使用MockWith注解

@MockWith注释的功能是为测试显式指定Mock容器通常用于测试类或Mock容器类没有在标准约定位置的情况以下列举几种典型使用场景。

1. 非标准位置的Mock容器类

TestableMock会依次在以下两个位置寻找Mock容器

  • 测试类中名为Mock的静态内部类(譬如原类型是Demo,测试类是DemoTestMock容器类为DemoTest.Mock
  • 同包路径下寻找名为被测类+Mock的外部类(譬如原类型是Demo,测试类是DemoTestMock容器类为DemoMock

倘若实际要使用的Mock容器类不在这两个位置就需要在测试类上使用@MockWith注释了。一般来说造成Mock容器类不在默认位置的原因可能有两种复用Mock容器、集中管理Mock容器。

当对一批功能近似的类型进行测试的时候由于需要进行Mock的外部调用基本一致可以将这些类型所需的所有Mock方法集中写在一个Mock容器类里然后让相关测试类共同引用这个公共Mock容器。详见复用Mock类与方法文档。

另一种情况是开发者希望将Mock方法的定义与测试类本身分开以便进行集中管理或规避某些扫描工具的路径规则譬如形成下面这种目录结构

src/
  main/
    com/
      demo/
        service/
          DemoService.java
  test/
    com/
      demo/
        service/
          DemoServiceTest.java
      mock/
        service/
          DemoServiceMock.java

此时就需要在测试类上显式的指定相应的Mock容器类了这种场景在实际情况中比较少见。

2. 非标准位置的测试类

TestableMock在建立“被测类”、“测试类”、“Mock容器类”之间关联的过程中为了识别被测类的位置约定测试类应当与被测类在相同的包路径且名称为被测类+Test。当实际情况不符合这种约定的时候,就需要通过在被测类上添加@MockWith注解来显式的建立关联。例如:

@MockWith(ServiceTest.Mock.class)
public class DemoService {
    ...
}

public class ServiceTest {
    public static class Mock extends BasicMock {
        ...
    }
}

注意:

  1. @MockWith注解通常是使用在测试类上,但这种情况下需要用在被测类上
  2. @MockWith指向的目标始终是Mock容器类而不是测试类
  3. @MockWith默认使用被注解类名字的尾缀判断当前类是被测类(名字非Test结尾)还是测试类(名字Test结尾),若遇到不符合此规则的类型,应使用注解的treatAs参数显式的指定(ClassType.SourceClass-被测类/ClassType.TestClass-测试类)

更进一步来说若出现测试类与Mock容器类均不在约定位置的时候则需要同时在测试类被测类上都使用@MockWith指向同一个Mock容器类来建立三者的关联但这种场景在实际运用中很少会遇到。

3. 使用不包含Mock方法的Mock容器类

为了加快搜索Mock容器类的速度在扫描过程中TestableMock只会将自身定义有Mock方法包含@MockMethod@MockMockConstructor注解的方法)以及明确被@MockWith指向的类识别为有效的Mock容器而不会去遍历其父类。

对于某些特殊情况譬如希望将实际Mock方法均定义在父类实际使用的子容器仅仅重载父类的某些特定方法此时即使Mock容器类的位置符合约定为了能够被识别依然应该在相应的测试类上增加对Mock容器类的@MockWith引用。