1. 程式人生 > >Springboot單元測試(MockBean||SpyBean)

Springboot單元測試(MockBean||SpyBean)

比較 spa obj 影響 package error java 執行 str

轉載:https://blog.csdn.net/maiyikai/article/details/78483423

本來要寫springboot集成netty實現的,但是想起來單元測試沒總結,那就趁此機會總結一下,不用文字了,直接用代碼去實現:
創建一個放方法的類MethodTest.java:(命名不嚴謹,能看懂就行了)

package com.mtk.netty.test;

import org.springframework.stereotype.Component;

@Component
public class MethodTest {

    //主方法
    public String gg(boolean flag){
        System.err.println("coming.........");
        String d = g(flag);//子方法
        h();
        System.err.println("result data is "+d);
        return d;
    }

    public String g(boolean flag){
        System.err.println("coming.........g");
        if(flag){
            throw new IllegalAccessError();//flag為true時拋異常
        }
        return "d";
    }

    public void h(){
        System.err.println("coming.........h");
    }
}

使用上邊的方法類,寫單元測試:
這裏時spy方式:

package com.mtk.netty.test;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.SpyBean;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;

import com.myk.Application;

/**
 * 使用spy方式
 * @author maiyikai 2017.11.08
 *
 */
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = Application.class)
@WebAppConfiguration
public class SpyTest {
    //gg(boolean)方法:控制臺打印: coming.........
    //g(boolean)方法:控制臺打印: coming.........g
    //h()方法:控制臺打印: coming.........h
    //gg(boolean)方法在g(boolean)和h()方法執行完之後:控制臺打印: result data is *

    /**
     * 使用代理:如下方式
     * 或Mockito.spy(MethodTest.class)獲得代理對象
     */
    @SpyBean
    private MethodTest spyTest;

    /**
     * 不代理,直接運行程序
     * 控制臺打印:
     *  coming.........
     *  coming.........g
     *  coming.........h
     *  result data is d
     *  d
     */
    @Test
    public void test(){
        System.err.println(spyTest.gg(false));
    }

    /**
     * 不使用代理:讓g方法拋異常
     * 控制臺打印
     * coming.........
     * coming.........g
     * 由於拋異常,程序中斷
     */
    @Test
    public void test2(){
        System.err.println(spyTest.gg(true));
    }

    /**
     * 使用代理對象,代理g方法,並讓其返回“test”
     * 第一種方式:使用thenReturn("test");
     * 控制臺打印:
     * coming.........g
     * coming.........
     * coming.........h
     * result data is test
     * test
     * 
     */
    @Test
    public void test3(){
        Mockito.when(spyTest.g(false)).thenReturn("test");

        System.err.println(spyTest.gg(false));
    }
    /**
     * 使用代理對象,代理g方法,並讓其返回“test”
     * 第二種方式:使用doReturn("test");
     * 其中doReturn("test")後執行.when(spyTest).g(false)方法
     * 控制臺打印:
     * coming.........
     * coming.........h
     * result data is test
     * test
     * 
     */
    @Test
    public void test4(){
        Mockito.doReturn("test").when(spyTest).g(false);
        System.err.println(spyTest.gg(false));
    }
    /**
     * test3-test4比較
     * 正常執行順序
     *  coming.........
     *  coming.........g
     *  coming.........h
     *  result data is d
     *  d
     * 使用Mockito.when(spyTest.g(false)).thenReturn("test");方式
     * g(boolean)方法會在調用主方法gg(boolean)前執行,不管執行的結果是啥,都會按照mock的數據“test”返回
     * 
     * 使用Mockito.doReturn("test").when(spyTest).g(false);方式
     * g(boolean)方法不會被執行,當時會將它的返回值賦值為:“test”。
     * 在主方法gg(boolean)執行到g(boolean)時,不執行g(boolean)方法體,直接將值“test‘”返回。後續方法照常執行 
     */
//#######################################################################################   
    /**
     * 使用代理對象,代理gg方法,並讓其返回“test”
     * 第一種方式:使用thenReturn("test");
     * 控制臺打印:
     * coming.........g
     * 
     */
    @Test
    public void test5(){
        Mockito.when(spyTest.g(true)).thenReturn("test");
        System.err.println(spyTest.gg(true));
    }

    /**
     * 使用代理對象,代理gg方法,並讓其返回“test”
     * 第二種方式:使用doReturn("test");
     * 其中doReturn("test")後執行.when(spyTest).g(true)方法--拋異常
     * 控制臺打印:
     * coming.........
     * coming.........h
     * result data is test
     * test
     * 
     */
    @Test
    public void test6(){
        Mockito.doReturn("test").when(spyTest).g(true);
        System.err.println(spyTest.gg(true));
    }

    /**
     * test5-test6比較
     * 故意賦值讓其方法拋異常。
     * 正常執行順序
     *  coming.........
     *  coming.........g
     *  coming.........h
     *  result data is d
     *  d 
     * 
     *  因為:Mockito.when(spyTest.g(true)).thenReturn("test");會執行方法體的內容,則g(boolean)方法體會被執行,會拋出異常中斷程序運行
     *  而Mockito.doReturn("test").when(spyTest).g(true);方法體不會被執行,則不會拋出異常,不會造成程序中斷
     */

    //##################################無返回值######################
    /**
     * 無返回值方法的代理
     * 方法為h()
     * 因此方法對代碼不造成任何影響,所以可以不執行它
     * 可以使用:doNothing
     * 代碼:Mockito.doNothing().when(spyTest).h();
     */
    @Test
    public void test7(){
        Mockito.doNothing().when(spyTest).h();

        System.err.println(spyTest.gg(false));
    }

    /**
     * 測試
     * coming.........
     * coming.........g
     * result data is d
     * d
     */
    @Test
    public void test10(){
        Mockito.doReturn("23").when(spyTest).g(true);
        Mockito.doNothing().when(spyTest).h();

        System.err.println(spyTest.gg(false));
    }
}

這裏時mock的方式:

package com.mtk.netty.test;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;

import com.myk.Application;

/**
 * 使用mock方式
 * @author maiyikai 2017.11.08
 *
 */
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = Application.class)
@WebAppConfiguration
public class MockTest {

    //gg(boolean)方法:控制臺打印: coming.........
    //g(boolean)方法:控制臺打印: coming.........g
    //h()方法:控制臺打印: coming.........h
    //gg(boolean)方法在g(boolean)和h()方法執行完之後:控制臺打印: result data is *


        /**
         * 使用代理:如下方式
         * 或Mockito.mock(MethodTest.class)獲得代理對象
         */
        @MockBean
        private MethodTest mockTest;



        /**
         * 使用mock方式將會把對象給mock掉,則對象中的方法將不會被執行,但是使用到某方法時可以mock值,供調用方法使用
         */

        /**
         * 訪問主方法體gg(boolean)
         * 返回null
         */
        @Test
        public void test1(){
            System.err.println(mockTest.gg(false));
        }

        /**
         * mock方法gg(boolean),使其在使用到gg(boolean)方法時,返回:"test"
         */
        @Test
        public void test2(){
            Mockito.when(mockTest.gg(false)).thenReturn("test");

            System.err.println(mockTest.gg(false));
        }
        /**
         * mock方法gg(boolean),使其在使用到gg(boolean)方法時,返回:"test"
         */
        @Test
        public void test3(){
            Mockito.doReturn("test").when(mockTest).gg(false);

            System.err.println(mockTest.gg(false));
        }
        /**
         * mock方法gg(boolean),使其在使用到gg(boolean)方法時,返回:"test"
         */
        @Test
        public void test4(){
            Mockito.when(mockTest.gg(false)).thenAnswer(new Answer<String>() {
                //Answer<T>   T為方法的返回值類型
                @Override
                public String answer(InvocationOnMock invocation) throws Throwable {
                    return "test";
                }
            });

            System.err.println(mockTest.gg(false));
        }
        /**
         * mock方法gg(boolean),使其在執行到此方法時拋出自定義異常
         */
        @Test
        public void test5(){
            Mockito.when(mockTest.gg(false)).thenThrow( new IllegalArgumentException("單元測試異常"));

            System.err.println(mockTest.gg(false));
        }

        //對與返回值類型為void的操作有
        //1.直接mock對象,即此對象中所有的方法都不會被執行
        //2.使用Mockito.doNothing().when(mockObject).method();標記執行該方法時不做任何操作
}

因時間有限,寫了一些簡單的操作;
寫單元測試的過程中,有想過“只需要mock方法類中的某個方法,其他的方法不受影響”;之前使用MockBean就出問題了,研究了一下使用SpyBean就可以使用了,可以看上邊的例子就可以知道了。
springboot的文檔介紹也是可以看的:https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html “springboot
我的項目上傳地址:http://download.csdn.net/download/maiyikai/10110450

Springboot單元測試(MockBean||SpyBean)