首页 > 其他分享 >各种Mock方法对比

各种Mock方法对比

时间:2022-08-20 19:46:34浏览次数:58  
标签:对比 Mockito void hello class mock 方法 public Mock

各种Mock方法对比

1. EasyMock

  • 先录制, 后播放
  • 无法mock静态方法, 构造器等
  • 过程随着程序逻辑变复杂
public class HelloTest {
    @Test
    public void world() {
        // 1.生成mock对象
        Hello hello = createMock(Hello.class);
        // 2.设置预期行为和输出(录制)
        expect(hello.hello("a")).andReturn("hello a mock");
        expect(hello.hello("b")).andReturn("hello b mock");
        // 3.把mock对象切换到播放模式
        replay(hello);
        // 4.调用mock对象
        assertEquals("hello a mock", hello.hello("a"));
        assertEquals("hello b mock", hello.hello("b"));
        // 5.验证mock对象的行为,包含执行的方法和次数
        verify(hello);
    }
}

2. Mockito

  • spring默认Mock框架
  • 无法mock静态方法, 构造器等
@RunWith(MockitoJUnitRunner.class)
public class HelloTest {

    @Mock
    private Hello hello;

    @Before
    public void setUp() {
        // 初始化逻辑
    }

    @Test
    public void hello() {
        Mockito.when(hello.hello("a")).thenReturn("hello a mock");
        // 局部执行真实方法
        Mockito.when(hello.hello("b")).thenCallRealMethod();
        assertEquals("hello a mock", hello.hello("a"));
        assertEquals("hello b", hello.hello("b"));

        // 验证调用次数
        // 提供anyString()等参数匹配器
        Mockito.verify(hello, times(2)).hello(anyString());

        // 验证调用顺序
        InOrder inOrder = Mockito.inOrder(hello);
        inOrder.verify(hello).hello("a");
        inOrder.verify(hello).hello("b");
    }

    @Test
    public void hello_spy1() {
        Hello spy = Mockito.spy(new Hello());
        // 实际会执行hello("a")方法,只是mockito在最后替换了返回值
        Mockito.when(spy.hello("a")).thenReturn("hello a mock");
        assertEquals("hello a mock", spy.hello("a"));
        assertEquals("hello b", spy.hello("b"));
    }

    @Test
    public void hello_spy2() {
        Hello spy = Mockito.spy(new Hello());
        // 实际不会执行hello("a")方法
        Mockito.doReturn("hello a mock").when(spy).hello("a");
        assertEquals("hello a mock", spy.hello("a"));
        assertEquals("hello b", spy.hello("b"));
    }

    @Test(expected = RuntimeException.class)
    public void hello_exception() {
        Mockito.when(hello.hello("a")).thenThrow(new RuntimeException());
        hello.hello("a");
    }
}

3. PowerMock

  • 用于在EasyMock和Mockito的基础上添加静态, 构造器等mock
  • 理论上不应该mock静态方法, 构造器等, 先调整结构

3.1 mock普通方法

// 1.必须使用PowerMockRunner
@RunWith(PowerMockRunner.class)
// 2.这里填调用被测试方法的类
@PrepareForTest({CallNewHello.class})
public class CallNewHelloTest {
    @Test
    public void hello() throws Exception {
        Hello hello = Mockito.mock(Hello.class);
        // 提供withNoArguments/withAnyArguments/withArguments/withParameterTypes等构造参数设置方式
        PowerMockito.whenNew(Hello.class).withNoArguments().thenReturn(hello);
        Mockito.when(hello.hello("a")).thenReturn("hello a mock");
        CallNewHello callNewHello = new CallNewHello();
        assertEquals("hello a mock", callNewHello.hello("a"));
    }
}

3.2 mock静态方法

@RunWith(PowerMockRunner.class)
// 这里填需要mock的静态类
@PrepareForTest({HelloStatic.class})
public class HelloStaticTest {
    @Test
    public void hello() {
        PowerMockito.mockStatic(HelloStatic.class);
        Mockito.when(HelloStatic.hello("a")).thenReturn("hello a mock");
        Mockito.when(HelloStatic.hello("b")).thenReturn("hello b mock");
        assertEquals("hello a mock", HelloStatic.hello("a"));
        assertEquals("hello b mock", HelloStatic.hello("b"));
        // 校验是否调用HelloStatic.hello("a")及次数是否为1
        PowerMockito.verifyStatic(HelloStatic.class, Mockito.times(1));
        HelloStatic.hello("a");
        // 校验是否调用HelloStatic.hello("b")及次数是否为1
        PowerMockito.verifyStatic(HelloStatic.class, Mockito.times(1));
        HelloStatic.hello("b");
    }
}

3.3 mock单例

@RunWith(PowerMockRunner.class)
@PrepareForTest({HelloSingleton.class})
public class HelloSingletonTest {
    @Test
    public void hello() throws Exception {
        // mock构造函数要放在mockStatic前,否则构造函数内的代码会执行
        PowerMockito.whenNew(HelloSingleton.class).withNoArguments().thenReturn(null);
        HelloSingleton hello = Mockito.mock(HelloSingleton.class);
        // mock静态方法getInstance()的返回
        PowerMockito.mockStatic(HelloSingleton.class);
        Mockito.when(HelloSingleton.getInstance()).thenReturn(hello);
        Mockito.when(hello.hello("a")).thenReturn("hello a mock");
        assertEquals("hello a mock", HelloSingleton.getInstance().hello("a"));
        // 验证HelloSingleton.getInstance()是否被调用
        PowerMockito.verifyStatic(HelloSingleton.class, Mockito.times(1));
        HelloSingleton.getInstance();
        // 验证hello的mock对象是否调用hello("a")
        // 两者结合相当于验证HelloSingleton.getInstance().hello("a")
        Mockito.verify(hello).hello("a");
    }
}

3.4 mock私有方法

@RunWith(PowerMockRunner.class)
@PrepareForTest({HelloPrivate.class})
public class HelloPrivateTest {
    @Test
    public void hello() throws Exception {
        HelloPrivate hello = PowerMockito.mock(HelloPrivate.class);
        PowerMockito.when(hello, "privateHello", "a").thenReturn("hello a mock");
        Mockito.doCallRealMethod().when(hello).hello("a");
        assertEquals("hello a mock", hello.hello("a"));
        PowerMockito.verifyPrivate(hello, Mockito.times(1)).invoke("privateHello", "a");
    }
}

4. Mock环境变量

4.1 surefire 配置静态环境变量

public class EnvironmentTest {
    @Test
    public void test() {
        assertEquals("env_a_value", System.getenv("env_a"));
        assertEquals("property_a_value", System.getProperty("property_a"));
    }
}

4.2 system-rules 配置动态环境变量

public class EnvironmentTest {
    @Rule
    public final EnvironmentVariables environmentVariables = new EnvironmentVariables();

    @Test
    public void test() {
        environmentVariables.set("name", "value");
        assertEquals("value", System.getenv("name"));
    }

    @Rule
    public final ProvideSystemProperty myPropertyHasMyValue = new ProvideSystemProperty("MyProperty", "MyValue");

    @Rule
    public final ProvideSystemProperty otherPropertyIsMissing = new ProvideSystemProperty("OtherProperty", null);

    @Test
    public void test() {
        assertEquals("MyValue", System.getProperty("MyProperty"));
        assertNull(System.getProperty("OtherProperty"));
    }
}

5. Mockito集成spring

被测代码

@RestController
public class HelloController {
    @Autowired
    private HelloService helloService;

    @GetMapping(path = "/hello", produces = MediaType.TEXT_PLAIN_VALUE)
    public ResponseEntity<String> hello() {
        return new ResponseEntity<>(helloService.getName(), HttpStatus.OK);
    }

    @GetMapping(path = "/hello/static", produces = MediaType.TEXT_PLAIN_VALUE)
    public ResponseEntity<String> helloStatic() {
        return new ResponseEntity<>(HelloStatic.getName(), HttpStatus.OK);
    }
}

@Service
public class HelloService {
    public String getName() {
        return "hello";
    }
}

public class HelloStatic {
    public static String getName() {
        return "hello static";
    }
}

5.1 拉起springTest

// 这里需要使用SpringRunner
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
@AutoConfigureMockMvc
public class HelloControllerTest {
    @Autowired
    private MockMvc mockMvc;

    // 通过@MockBean注解替换Spring中的Bean为Mock对象
    @MockBean
    private HelloService helloServiceMock;

    @Before
    public void setUp() throws Exception {
        Mockito.when(helloServiceMock.getName()).thenReturn("world");
    }

    @Test
    public void hello() throws Exception {
        mockMvc.perform(get("/hello"))
            .andExpect(status().isOk())
            .andExpect(content().string("world"));
    }
}
@RunWith(PowerMockRunner.class)
// @RunWith 已经指定为 SpringRunner ,这时就需要 @PowerMockRunnerDelegate 注解代理SpringRunner
@PowerMockRunnerDelegate(SpringRunner.class)
@SpringBootTest
@PrepareForTest({HelloStatic.class})
@PowerMockIgnore({"javax.*", "com.sun.*", "org.xml.*", "org.w3c.*"})
@AutoConfigureMockMvc
public class HelloControllerTest {
    @Autowired
    private MockMvc mockMvc;

    @Before
    public void setUp() throws Exception {
        PowerMockito.mockStatic(HelloStatic.class);
        Mockito.when(HelloStatic.getName()).thenReturn("world static");
    }

    @Test
    public void hello() throws Exception {
        mockMvc.perform(get("/hello/static"))
            .andExpect(status().isOk())
            .andExpect(content().string("world static"));
    }
}

5.2 不拉起spring

public class HelloControllerTest {
    @Mock
    private HelloService helloService;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
        Mockito.when(helloService.getName()).thenReturn("world");
    }

    @Test
    public void hello() throws Exception {
        HelloController helloController = new HelloController(helloService);
        ResponseEntity<String> hello = helloController.hello();
        assertEquals(HttpStatus.OK, hello.getStatusCode());
        assertEquals("world", hello.getBody());
    }
}

6. mockHttp客户端请求

<dependency>
    <groupId>org.mock-server</groupId>
    <artifactId>mockserver-netty</artifactId>
    <version>5.10.0</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.mock-server</groupId>
    <artifactId>mockserver-junit-rule</artifactId>
    <version>5.10.0</version>
    <scope>test</scope>
</dependency>

被测代码

public class HelloHttp {
    private String host;
    private int port;
    public HelloHttp(String host, int port) {
        this.host = host;
        this.port = port;
    }

    public String hello() {
        CloseableHttpClient client = HttpClients.createDefault();
        HttpGet httpGet = new HttpGet("http://" + host + ":" + port + "/hello");
        try (CloseableHttpResponse response = client.execute(httpGet)) {
            return EntityUtils.toString(response.getEntity());
        } catch (IOException e) {
            System.out.println("http get error:" + e.getMessage());
        }
        return null;
    }
}
public class HelloHttpTest {
    private static final String HOST = "localhost";
    private static final int PORT = PORT;

    @Rule
    public MockServerRule server = new MockServerRule(this, PORT);
    
    @Test
    public void hello() {
        MockServerClient mockClient = new MockServerClient(HOST, PORT);
        mockClient.when(request().withPath("/hello").withMethod("GET"))
            .respond(response().withStatusCode(200).withBody("hello"));
        HelloHttp helloHttp = new HelloHttp(HOST, PORT);
        assertEquals("hello", helloHttp.hello());
    }
}

7. 组件提供的原生Mock工具(zk为例)

spring:
  application:
    name: hello
    cloud:
      zookeeper:
        connect-string: ip:port
        discovery:
          enabled: true
          register: true
<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-test</artifactId>
    <version>2.6.0</version>
    <scope>test</scope>
</dependency>
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
@AutoConfigureMockMvc
public class ApplicationTest {
    private static TestingServer server;

    @Autowired
    private MockMvc mockMvc;

    @BeforeClass
    public static void beforeClass() throws Exception {
        server = new TestingServer(2181, true);
    }

    @AfterClass
    public static void afterClass() throws Exception {
        server.stop();
    }

    @Test
    public void test() throws Exception {
        mockMvc.perform(get("/hello"))
            .andExpect(status().is2xxSuccessful())
            .andExpect(content().string("hello"));
    }
}

标签:对比,Mockito,void,hello,class,mock,方法,public,Mock
From: https://www.cnblogs.com/rellik96/p/16593065.html

相关文章

  • jQuery_ajax调用的几种方法
    一、$.ajax()的基础使用 <buttonid="btn">发送请求</button><scriptsrc="/js/jquery.min.js"></script><script>varparams={name:'wangwu',age:300}$('#bt......
  • jquery中attr方法和val方法的区别
    这几天一直在看jquery,感觉attr方法和val方法没有什么区别,经过试验,有点明白了这两个方法的区别!分享一下,如果理解错误,请大家指正!以下是源码:<!DOCTYPEhtml><html><head><......
  • 为方法增加一个超时等待
    为方法增加一个超时等待FindWindow查找窗口直接执行可能窗口还没有准备好,返回结果必然是0。通常使用Thread.Sleep进行阻塞等待,是一种有效的手段。因计算机CPU运算效率......
  • jQuery on()方法示例及jquery on()方法的优点
    https://www.jb51.net/article/71614.htm#jQueryon()方法是官方推荐的绑定事件的一个方法。1$(selector).on(event,childSelector,data,function,map)......
  • 分析lvgl的代码启动过程,对比esp32,stm32,linux
    lvgl是gui层负责绘制gui并根据输入设备的事件来响应重绘,然后把绘制的缓冲区发送给显示驱动去实际显示。以下代码参考lvglarduino官方例程,guiguider模拟器例程,,零知stm3......
  • js里面的三种注释方法
    https://www.cnblogs.com/rubylouvre/p/3649999.htmljavascript(js)语言里面的注释方法有三种。第一种是多行注释"/**/",一般js文件开头,介绍作者,函数等信息。/......
  • 不常见但很有用的chrome调试工具使用方法
     https://www.cnblogs.com/xiaohuochai/p/6344886.html前面的话  对于chrome调试工具,常用的是elements标签、console标签、sources标签和network标签。但实际上,还......
  • 如何将一个div水平垂直居中?6种方法做推荐
    https://www.cnblogs.com/Julia-Yuan/p/6648816.html方案一:div绝对定位水平垂直居中【margin:auto实现绝对定位元素的居中】,兼容性:,IE7及之前版本不支持di......
  • 实现a标签中的各种点击(onclick)事件的方法
    https://www.cnblogs.com/pengfei25/p/6018237.html 我们常用的在a标签中有点击事件:1.ahref="javascript:js_method();"这是我们平台上常用的方法,但是这种方法在传......
  • Unity-拓展方法
    拓展方法:在不破坏原始类的情况下,添加成员方法,只能添加成员方法。一般用于向已经封装好的程序集中添加新的方法usingUnityEngine;publicclassTest:MonoBehaviour{......