{"id":7742,"date":"2022-10-19T19:08:01","date_gmt":"2022-10-19T11:08:01","guid":{"rendered":"http:\/\/123.57.164.21\/?p=7742"},"modified":"2022-10-19T19:08:01","modified_gmt":"2022-10-19T11:08:01","slug":"springboot%e5%8d%95%e5%85%83%e6%b5%8b%e8%af%95-spybean-vs-mockbean","status":"publish","type":"post","link":"https:\/\/92it.top\/?p=7742","title":{"rendered":"SpringBoot\u5355\u5143\u6d4b\u8bd5: SpyBean vs MockBean"},"content":{"rendered":"\n<p><strong>\u95ee\u9898\u662f\u4ec0\u4e48\uff1f<\/strong><\/p>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p>\u5982\u4e0b\u662f\u5f85\u6d4b\u8bd5\u7c7b\uff0c\u671f\u671b\u6d4b\u8bd5<code>TestService<\/code>\u7684<code>test<\/code>\u65b9\u6cd5\uff0c\u4f46\u662f\u7531\u4e8e\u67d0\u79cd\u539f\u56e0\uff08\u4e0b\u4f8b\u4e2d\u7684<code>doSomething<\/code>\uff09\u65e0\u6cd5\u7b80\u5355\u7684\u88ab\u6267\u884c\u3002 \u6240\u4ee5\u5e0c\u671b<code>test<\/code>\u65b9\u6cd5\u771f\u5b9e\u6267\u884c\uff0c\u800c\u4e3a<code>doSomething<\/code>\u65b9\u6cd5\u6253\u6869\u3002<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">package com.example.demo.service;\n\nimport com.example.demo.repositroy.TestRepository;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class TestService {\n    private final TestRepository testRepository;\n\n    public TestService(TestRepository testRepository) {\n        this.testRepository = testRepository;\n    }\n\n    public String doSomething(){\n        \/\/\u5047\u88c5\u6709\u590d\u6742\u7684\u65e0\u6cd5\u6267\u884c\u7684\u4e1a\u52a1\u903b\u8f91\n        testRepository.doSomething();\n        throw new RuntimeException();\n    }\n\n    public String test() {\n        doSomething();\n        \/\/\u5176\u4ed6\u903b\u8f91\n        return \"id\";\n    }\n}\n<\/pre>\n\n\n\n<p><strong>\u5982\u4f55\u89e3\u51b3\uff1f<\/strong><\/p>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p><strong>\u4f7f\u7528MockBean<\/strong><\/p>\n\n\n\n<p>\u5982\u679c\u4ec5\u4f7f\u7528<code>@MockBean<\/code>\u5c06\u4fee\u9970\u7684\u5bf9\u8c61mock\u6389\uff0c\u8fd9\u6837<code>TestService<\/code>\u7684<code>doSomething()<\/code>\u65b9\u6cd5\u5c31\u4e0d\u518d\u6267\u884c\u5177\u4f53\u7684\u7ec6\u8282\uff0c\u4f46\u662f<code>MockBean<\/code>\u4f1a\u5c06\u76ee\u6807\u5bf9\u8c61\u7684\u6240\u6709\u65b9\u6cd5\u5168\u90e8mock\uff0c\u6240\u4ee5<code>test<\/code>\u4e0d\u80fd\u771f\u5b9e\u5730\u88ab\u6267\u884c\uff0c\u4e5f\u5c31\u65e0\u6cd5\u6d4b\u8bd5\u4e86\u3002<\/p>\n\n\n\n<p>\u800c<code>when...thenCallRealMethod<\/code>\u53ef\u8fbe\u5230\u90e8\u5206mock\u7684\u6548\u679c\uff0c\u4ec5<code>test<\/code>\u65b9\u6cd5\u771f\u5b9e\u6267\u884c\u3002<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">@SpringBootTest\n@RunWith(SpringRunner.class)\npublic class TestServiceTest {\n    @MockBean\n    TestService testService;\n\n    @Test\n    public void test(){\n        when(testService.test()).thenCallRealMethod();\n        assertThat(testService.test(), equalTo(\"id\"));\n    }\n}\n<\/pre>\n\n\n\n<p><strong>\u4f7f\u7528SpyBean<\/strong><\/p>\n\n\n\n<p>\u4f7f\u7528<code>@SpyBean<\/code>\u4fee\u9970\u7684<code>testService<\/code>\u662f\u4e00\u4e2a\u771f\u5b9e\u5bf9\u8c61\uff0c\u4ec5\u5f53<code>doReturn(\"\").when(testService).doSomething()<\/code>\u65f6\uff0c<code>doSomething<\/code>\u65b9\u6cd5\u88ab\u6253\u6869\uff0c\u5176\u4ed6\u7684\u65b9\u6cd5\u4ecd\u88ab\u771f\u5b9e\u8c03\u7528\u3002<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">@SpringBootTest\n@RunWith(SpringRunner.class)\npublic class TestServiceTest {\n    @SpyBean\n    TestService testService;\n\n    @Test\n    public void test(){\n        doReturn(\"\").when(testService).doSomething();\n        assertThat(testService.test(), equalTo(\"id\"));\n    }\n}\n<\/pre>\n\n\n\n<p><strong>\u5c0f\u9677\u9631<\/strong><\/p>\n\n\n\n<p>\u4e0e\u4f7f\u7528<code>@MockBean<\/code>\u4e0d\u540c\uff0c\u4e0a\u8282\u4e2d\u8c03\u7528<code>doReturn(\"\").when(testService).doSomething()<\/code>\u00a0\u65f6<code>doSomething<\/code>\u65b9\u6cd5\u88ab\u6253\u6869\u3002\u800c<code>when(testService.doSomething()).thenReturn(\"\")<\/code>\u5219\u8fbe\u4e0d\u5230\u6b64\u6548\u679c\u3002\u539f\u56e0\u662f\uff1a\u4f7f\u7528<code>@SpyBean<\/code>\u4fee\u9970\u7684<code>testService<\/code>\u662f\u4e00\u4e2a\u771f\u5b9e\u5bf9\u8c61\uff0c\u6240\u4ee5<code>testService.doSomething()<\/code>\u4f1a\u88ab\u771f\u5b9e\u8c03\u7528\u3002<\/p>\n\n\n\n<p><strong>Mockito\u5b98\u65b9\u6587\u6863\u4e0a\u8fd9\u6837\u8bf4\uff1a<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">Sometimes it's impossible or impractical to use when(Object) for stubbing spies. Therefore when using spies please consider doReturn|Answer|Throw() family of methods for stubbing. Example:\n<\/pre>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">List list = new LinkedList();\nList spy = spy(list);\n\n\/\/Impossible: real method is called so spy.get(0) throws IndexOutOfBoundsException (the list is yet empty)\nwhen(spy.get(0)).thenReturn(\"foo\");\n\n\/\/You have to use doReturn() for stubbing\ndoReturn(\"foo\").when(spy).get(0);<\/pre>\n\n\n\n<pre class=\"wp-block-preformatted\">Mockito does not delegate calls to the passed real instance, instead it actually creates a copy of it. So if you keep the real instance and interact with it, don't expect the spied to be aware of those interaction and their effect on real instance state. The corollary is that when an unstubbed method is called on the spy but not on the real instance, you won't see any effects on the real instance. Watch out for final methods. Mockito doesn't mock final methods so the bottom line is: when you spy on real objects + you try to stub a final method = trouble. Also you won't be able to verify those method as well.\n<\/pre>\n\n\n\n<p><strong>\u6982\u62ec\u4e00\u4e0b\uff1a<\/strong><\/p>\n\n\n\n<ul><li>\u5f53\u4f7f\u7528spy\u65f6\uff0c\u8003\u8651\u4f7f\u7528<code>doReturn|Answer|Throw()<\/code><\/li><li>spy\u4fee\u9970\u7684\u53d8\u91cf\uff0cMockito\u4f1a\u91cd\u65b0\u521b\u5efa\u4e00\u4e2a\u5b9e\u4f8b\u7684copy\uff0c\u5e76\u4e0d\u76f4\u63a5\u4f5c\u7528\u4e8e\u771f\u5b9e\u5b9e\u4f8b<\/li><li>spy\u5bf9final\u65b9\u6cd5\u65e0\u6548<\/li><\/ul>\n\n\n\n<p><strong>SpyBean vs MockBean<\/strong><\/p>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p><code>SpyBean<\/code>\u548c<code>MockBean<\/code>\u662f<code>spring-boot-test<\/code>\u5305\u6240\u63d0\u4f9b\u7684\u4e24\u4e2a\u6ce8\u89e3\uff0c\u7528\u4e8eSpy\u6216Mock Spring\u5bb9\u5668\u6240\u7ba1\u7406\u7684\u5b9e\u4f8b\u3002\u800cSpy\u4e0eMock\u7684\u65b9\u5f0f\u6b63\u597d\u76f8\u53cd\uff0cspy\u9ed8\u8ba4\u6240\u6709\u65b9\u6cd5\u5747\u771f\u5b9e\u8c03\u7528\uff0cMock\u9ed8\u8ba4\u6240\u6709\u65b9\u6cd5\u5747\u8c03\u7528mock\u7684\u5b9e\u73b0\u3002 \u4f7f\u7528\u573a\u666f\u4e0a\u6709\u4ec0\u4e48\u533a\u522b\u5462\uff1f\u57fa\u4e8e\u4e0a\u4f8b\uff0c\u867d\u7136\u4e24\u8005\u90fd\u80fd\u5b9e\u73b0\uff0c\u4f46<code>SpyBean<\/code>\u66f4\u5408\u9002\uff0c\u56e0\u4e3a\u4e0a\u4f8b\u5728\u6d4b\u8bd5<code>TestService<\/code>\uff0c\u6240\u4ee5<code>testService<\/code>\u4e0d\u5e94\u8be5\u662f\u4e00\u4e2a\u5b8c\u5168\u88abmock\u7684\u5b9e\u4f8b\u3002\u800c\u5982\u679c\u5728<code>TestService<\/code>\u7684\u6d4b\u8bd5\u7528\u529b\u4e2d\u60f3\u8981Mock\u00a0<code>TestRepository<\/code>\uff0c\u4f7f\u7528<code>MockBean<\/code>\u5c31\u6bd4\u8f83\u5408\u9002\u4e86\u3002<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">\u4e3a\u6d4b\u8bd5\u4e3b\u4f53\u7c7b\u90e8\u5206\u6253\u6869\u8003\u8651\u4f7f\u7528SpyBean, \u4e3a\u5916\u90e8\u4f9d\u8d56\u6253\u6869\uff0c\u8003\u8651\u4f7f\u7528MockBean\u3002\n<\/pre>\n\n\n\n<p><strong>\u603b\u7ed3<\/strong><\/p>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<ul><li><code>SpyBean<\/code>\u548c<code>MockBean<\/code>\u662f<code>spring-boot-test<\/code>\u5305\u6240\u63d0\u4f9b\u7684\u4e24\u4e2a\u6ce8\u89e3\uff0c\u7528\u4e8eSpy\u6216Mock Spring\u5bb9\u5668\u6240\u7ba1\u7406\u7684\u5b9e\u4f8b\uff1b<\/li><li>\u4f7f\u7528<code>SpyBean<\/code>\u6216\u8005<code>Spy<\/code>\u65f6\uff0c\u5f53\u9700\u8981\u5bf9\u67d0\u4e2a\u65b9\u6cd5\u8fdb\u884c\u6253\u6869\u65f6\uff0c\u9700\u8981\u6ce8\u610f\u4e00\u4e9b\u4f7f\u7528\u9650\u5236\uff1b<\/li><li>\u4e3a\u6d4b\u8bd5\u4e3b\u4f53\u7c7b\u90e8\u5206\u6253\u6869\u8003\u8651\u4f7f\u7528<code>SpyBean<\/code>,\u4e3a\u5916\u90e8\u4f9d\u8d56\u6253\u6869\uff0c\u8003\u8651\u4f7f\u7528<code>MockBean<\/code>\u3002<\/li><\/ul>\n","protected":false},"excerpt":{"rendered":"<p>\u95ee\u9898\u662f\u4ec0\u4e48\uff1f \u5982\u4e0b\u662f\u5f85\u6d4b\u8bd5\u7c7b\uff0c\u671f\u671b\u6d4b\u8bd5TestService\u7684test\u65b9\u6cd5\uff0c\u4f46\u662f\u7531\u4e8e\u67d0\u79cd\u539f\u56e0\uff08\u4e0b\u4f8b\u4e2d\u7684doSo [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[26,27],"tags":[],"_links":{"self":[{"href":"https:\/\/92it.top\/index.php?rest_route=\/wp\/v2\/posts\/7742"}],"collection":[{"href":"https:\/\/92it.top\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/92it.top\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/92it.top\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/92it.top\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=7742"}],"version-history":[{"count":1,"href":"https:\/\/92it.top\/index.php?rest_route=\/wp\/v2\/posts\/7742\/revisions"}],"predecessor-version":[{"id":7743,"href":"https:\/\/92it.top\/index.php?rest_route=\/wp\/v2\/posts\/7742\/revisions\/7743"}],"wp:attachment":[{"href":"https:\/\/92it.top\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=7742"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/92it.top\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=7742"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/92it.top\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=7742"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}