Junit梁剔、AssertJ、Hamcrest舞蔽、Mockito荣病、PowerMock、spring boot test淺談

源碼 github: https://github.com/lotusfan/junit-demo test目錄

JUnit

JUnit 5的運(yùn)行條件是Java 8環(huán)境渗柿。

JUnit4 與 JUnit 5 常用注解對(duì)比

JUnit4 Junit5 說明
@Test @Test 表示該方法是一個(gè)測(cè)試方法
@BeforeClass @BeforeAll 表示使用了該注解的方法應(yīng)該在當(dāng)前類中所有使用了@Test个盆、@RepeatedTest、@ParameterizedTest或者@TestFactory注解的方法之前 執(zhí)行朵栖;
@AfterClass @AfterAll 表示使用了該注解的方法應(yīng)該在當(dāng)前類中所有使用了@Test颊亮、@RepeatedTest、@ParameterizedTest或者@TestFactory注解的方法之后執(zhí)行陨溅;
@Before @BeforeEach 表示使用了該注解的方法應(yīng)該在當(dāng)前類中每一個(gè)使用了@Test终惑、@RepeatedTest、@ParameterizedTest或者@TestFactory注解的方法之前 執(zhí)行
@After @AfterEach 表示使用了該注解的方法應(yīng)該在當(dāng)前類中每一個(gè)使用了@Test门扇、@RepeatedTest雹有、@ParameterizedTest或者@TestFactory注解的方法之后 執(zhí)行
@Ignore @Disabled 用于禁用一個(gè)測(cè)試類或測(cè)試方法
@Category @Tag 用于聲明過濾測(cè)試的tags,該注解可以用在方法或類上悯嗓;類似于TesgNG的測(cè)試組或JUnit 4的分類件舵。
@Parameters @ParameterizedTes 表示該方法是一個(gè)參數(shù)化測(cè)試
@RunWith @ExtendWith @Runwith就是放在測(cè)試類名之前,用來確定這個(gè)類怎么運(yùn)行的
@Rule @ExtendWith Rule是一組實(shí)現(xiàn)了TestRule接口的共享類脯厨,提供了驗(yàn)證铅祸、監(jiān)視TestCase和外部資源管理等能力
@ClassRule @ExtendWith @ClassRule用于測(cè)試類中的靜態(tài)變量,必須是TestRule接口的實(shí)例合武,且訪問修飾符必須為public临梗。

AssertJ

示例

class People {

    public People(int age, String name) {
        this.age = age;
        this.name = name;
    }

    public People() {
    }

    int age;
    String name;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
assertThat 斷言的構(gòu)造
   /**
     * AbstractObjectAssert:as 描述斷言判定失敗時(shí)自定義內(nèi)容
     *
     */
    @Test
    public void assertThatTest() {
        People people = new People();
        people.setAge(10);
        people.setName("fan");
        assertThat(people.getAge()).as("check age %d", people.getAge()).isEqualTo(10);

    }
filteredOn 過濾器
   /**
     * ListAssert: filteredOn
     * contains、containsAnyOf稼跳、containsOnlyOnce
     *
     */
    @Test
    public void assertThatFilteredOn() {

        People people = new People(10, "a");
        People people1 = new People(20, "b");
        List<People> peopleList = Arrays.asList(people, people1);

        //filteredOn(String propertyOrFieldName,FilterOperator<?> filterOperator)
        //FilterOperator: 構(gòu)造  InFilter.in盟庞、NotFilter.not、NotInFilter.notIn
        assertThat(peopleList).filteredOn("age", in(10)).containsOnly(people);
        assertThat(peopleList).filteredOn(p -> p.getAge() == 20).containsOnly(people1);

    }
inPredicate
    /**
     * PredicateAssert: accepts 接收數(shù)據(jù)汤善,如果滿足test條件校驗(yàn)成功
     */
    @Test
    public void assertThatInPredicate() {
        List<String> list = Arrays.asList("aaa", "bbb");
        Predicate<List<String>> predicate = t -> {
            System.out.println(t);
            return t.contains("aaa") || t.contains("bbb");
        };
        assertThat(predicate).accepts(list);

        assertThat((Predicate) p -> true).rejects("bbbb");

        /**
         * 于此類似的還有AssertJ封裝了IntPredicate什猖、LongPredicate票彪、DoublePredicate
         */
        assertThat((IntPredicate) pi -> pi > 0).accepts(3, 4);

    }
InOptional
    /**
    * OptionalAssert:isPresent、isNotEmpty不狮、containst等
    */
    @Test
    public void assertThatInOptional() {
    //        Optional op = Optional.ofNullable(new People());
       Optional op = Optional.ofNullable("aaa");
    //        assertThat(op).isEmpty();
       assertThat(op).isNotEmpty().contains("aaa");
    }
extracting降铸、tuple 元組組合
   @Test
   public void assertThatExtracting() {
       People people = new People(10, "a");
       People people1 = new People(20, "b");
       List<People> peopleList = Arrays.asList(people, people1);
    
       assertThat(peopleList).extracting("name", "age").contains(tuple("a", 10)).doesNotContain(tuple("c", "33"));
   }
   
   /**
    *  tuple只能用在extracting后,創(chuàng)建了一個(gè)元組
    *  Utility method to build nicely a {@link org.assertj.core.groups.Tuple} when working with
    * {@link org.assertj.core.api.IterableAssert#extracting(String...)} or
    * {@link org.assertj.core.api.ObjectArrayAssert#extracting(String...)}
    *
    */
   @Test
   public void assertThatTuple() {
       People p1 = new People(10, "a");
       People p2 = new People(20, "b");
       List<People> peopleList = Arrays.asList(p1, p2);
       assertThat(peopleList).extracting("name", "age").contains(tuple("a", 10));
   }
entry
   /**
     * MapAssert: contains摇零、containsAnyOf推掸、containsOnly、containsKeys驻仅、containsOnlyKeys谅畅、containsValues
     *
     * 注:
     * contains(Map.Entry<? extends KEY, ? extends VALUE>... entries) 入?yún)镸ap.entry,所以需要調(diào)用
     * Assertions:<K, V> MapEntry<K, V> entry(K key, V value) 構(gòu)造
     */
    @Test
    public void assertThatEntry() {
        Map<String, People> map = new HashMap<>();
        map.put("akey", new People(10, "a"));

        assertThat(map).containsAnyOf(entry("bkey", new People(20, "b")), entry("akey", map.get("akey")));
    }
atIndex List坐標(biāo)
  /**
    * Assertions: atIndex 使用在 AbstractListAssert: contains(ELEMENT value, Index index) 方法中的index構(gòu)造
    * 可能還有其它地方使用到
    */
   @Test
   public void assertThatAtIndex() {
    
       People p1 = new People(10, "a");
       People p2 = new People(20, "b");
       List<People> peopleList = Arrays.asList(p1, p2);
    
       assertThat(peopleList).extracting("name").contains("a", atIndex(0));
   }
returns 對(duì)象方法返回
   /**
     * AbstractObjectAssert: returns 驗(yàn)證 入?yún)?duì)象 調(diào)用方法返回值
     * from 構(gòu)造 Function
     */
    @Test
    public void assertThatReturns() {
        assertThat(new People(10, "a")).returns("b", from(People::getName));
    }
condition 自定義斷言
   /**
     * 自定義斷言
     * AbstractAssert is,isNot噪服,has毡泻,doesNotHave
     * AbstractObjectArrayAssert are,have芯咧,doNotHave牙捉,areAtLeast,haveExactly  集合條件
     *
     * condition組合 allOf anyOf doesNotHave not
     */
    @Test
    public void assertThatCondition() {
        People p1 = new People(10, "a");
        People p2 = new People(20, "b");
        List<People> peopleList = Arrays.asList(p1, p2);

        Condition<People> c1 = new Condition<>(people -> people.getName().equals("a"), "condition 1");
        Condition<People> c2 = new Condition<>(people -> people.getName().equals("b"), "condition 2");
        Condition<People> c3 = new Condition<>(people -> true, "condition 3");
        Condition<People> c4 = new Condition<>(people -> false, "condition 4");


        assertThat(peopleList).have(not(c4));
//        assertThat(peopleList).have(anyOf(c1, c2, c3));

    }
filter
   /**
     * Assertions:filter 按條件篩選數(shù)據(jù)并重新生成列表進(jìn)行校雞
     */

    @Test
    public void assertThatFilter() {
        People p1 = new People(10, "a");
        People p2 = new People(20, "b");
        List<People> peopleList = Arrays.asList(p1, p2);

        assertThat(filter(peopleList).and("name").equalsTo("a").and("age").equalsTo("10").get()).extracting("name").contains("b");
    }
fail
  /**
    * 異常
    * @throws Exception
    */
    @Test(expected = RuntimeException.class)
    public void expectedException() throws Exception {
       throw new Exception();
    }
    
    @Test(expected = RuntimeException.class)
    public void expectedExceptionSupper() {
       throw new RunExceptionSub();
    }
    
    @Test
    public void assertThatFail() {
    
       try {
           fail("異常", RuntimeException.class);
           throwRuntimeException();
       } catch (Exception e) {
    
       }
    }
    
    private void throwRuntimeException() {
       throw new RuntimeException();
    }
timeOut
/**
* 超時(shí)
*/
@Test(timeout = 1000)
public void timeOut() {
   try {
       Thread.sleep(2000);
   } catch (InterruptedException e) {
       e.printStackTrace();
   }

}
其它
  /**
     * AbstractBigDecimalAssert<?> assertThat(BigDecimal actual)
     * AbstractBigIntegerAssert<?>  assertThat(BigInteger actual)
     * AbstractUriAssert<?> assertThat(URI actual)
     * AbstractUrlAssert<?> assertThat(URL actual)
     * AbstractBooleanAssert<?> assertThat(boolean actual)
     * AbstractBooleanArrayAssert<?> assertThat(boolean[] actual)
     * AbstractByteAssert<?> assertThat(byte actual)
     * AbstractByteArrayAssert<?> assertThat(byte[] actual)
     * AbstractCharacterAssert<?> assertThat(char actual)
     * AbstractCharacterAssert<?> assertThat(Character actual)
     * ClassAssert assertThat(Class<?> actual)
     * AbstractDoubleAssert<?> assertThat(double actual)
     * AbstractDoubleArrayAssert<?> assertThat(double[] actual)
     * AbstractFileAssert<?> assertThat(File actual)
     * <p>
     * FutureAssert<RESULT> assertThat(Future<RESULT> actual)
     * <p>
     * AbstractInputStreamAssert<?, ? extends InputStream> assertThat(InputStream actual)
     * AbstractFloatAssert<?> assertThat(float actual)
     * AbstractFloatArrayAssert<?> assertThat
     * AbstractIntegerAssert<?> assertThat(int actual)
     * <p>
     * <ACTUAL extends Iterable<? extends ELEMENT>, ELEMENT, ELEMENT_ASSERT extends AbstractAssert<ELEMENT_ASSERT, ELEMENT>>
     * FactoryBasedNavigableIterableAssert<?, ACTUAL, ELEMENT, ELEMENT_ASSERT> assertThat(Iterable<? extends ELEMENT> actual,
     * AssertFactory<ELEMENT, ELEMENT_ASSERT> assertFactory)
     * <p>
     * <ELEMENT, ACTUAL extends List<? extends ELEMENT>, ELEMENT_ASSERT extends AbstractAssert<ELEMENT_ASSERT, ELEMENT>>
     * ClassBasedNavigableListAssert<?, ACTUAL, ELEMENT, ELEMENT_ASSERT> assertThat(List<? extends ELEMENT> actual,
     *
     */

注:jdk中所有對(duì)象基本都封了特定的Assert敬飒,基本類型還封裝了ArrayAssert 使用的時(shí)候可以因需而定

Hamcrest

Hamcest提供了一套匹配符Matcher邪铲,這些匹配符更接近自然語言,可讀性高无拗,更加靈活带到。

示例

anything
   /**
     * 總是匹配成功
     */
    @Test
    public void hamcrestAnything() {
        assertThat("failed message anything", "aa", anything());
        assertThat("failed message anything", null, anything());
    }
allOf
   /**
     * 全部 Marcher 匹配 才通過
     */
    @Test
    public void hamcrestAllof() {
        assertThat("aaa", allOf(notNullValue(), isEmptyString()));
    }
anyOf
   /**
     * 任意 Marcher 匹配 則通過
     */
    @Test
    public void hamcrestAnyof() {
        assertThat("aaa", anyOf(notNullValue(), isEmptyString()));
    }
not
   /**
     * 不等
     */
    @Test
    public void hamcrestNot() {
        assertThat("aaa", not("aaa"));
    }
equalTo
   /**
     * 對(duì)象 equalTo 返回是否相等
     */
    @Test
    public void hamcrestEqualTo() {
        Bicycle bicycle1 = new Bicycle() {
            @Override
            public boolean equals(Object obj) {
                return true;
            }
        };
        Bicycle bicycle2 = new Bicycle() {
            @Override
            public boolean equals(Object obj) {
                return true;
            }
        };

        assertThat(bicycle1, equalTo(bicycle2));
    }
hasToString
   /**
     * 對(duì)象 toString 返回 是否相等
     */
    @Test
    public void hamcrestHasToString() {

        Bicycle bicycle = new Bicycle() {
            @Override
            public String toString() {
                return "bicycle";
            }
        };

        assertThat(bicycle, hasToString("bicycle"));
    }
null
   /**
     * 對(duì)象 是否為null
     */
    @Test
    public void hamcrestNull() {
        assertThat(null, nullValue());
        assertThat("aaa", notNullValue());
    }
hasProperty
   /**
     * 測(cè)試JavaBeans屬性,而不是屬性值
     */
    @Test
    public void hamcrestHasProperty() {

        Bicycle bicycle = new Bicycle();

        assertThat(bicycle, hasProperty("type"));
    }
array
   /**
     * 數(shù)組的每一項(xiàng) 都要配置驗(yàn)證 Matcher
     */
    @Test
    public void hamcrestArray() {

        String[] strings = new String[]{"aaa", "bbb"};
        assertThat(strings, arrayWithSize(2));
        assertThat(strings, array(notNullValue(), is("bbb")));

    }
hasEntry
   /**
     * Map 包含
     * hasEntry, hasKey, hasValue
     */
    @Test
    public void hamcrestHasEntry() {
        Map<String, String> map = new HashMap<>();
        map.put("name", "zhang");

        assertThat(map, hasKey("name"));
        assertThat(map, hasValue("zhang"));
        assertThat(map, hasEntry("name", "zhang"));
    }
hasItem
   /**
     * 集合 包含
     */
    @Test
    public void hamcrestHasItem() {
        List<String> list = Arrays.asList("aaa", "bbb");

        assertThat(list, hasItem("aaa"));
        assertThat(list, hasItems("aaa", "bbb"));
    }
equalToIgnoringCase
   /**
     * 忽略 字符串 大小寫
     */
    @Test
    public void hamcrestEqualToIgnoringCase() {

        assertThat("aAa", equalToIgnoringCase("AAA"));
    }
equalToIgnoringWhiteSpace
   /**
     * 只忽略字符串 前、后 的空白英染,不包含 中間空格
     */
    @Test
    public void hamcrestEqualToIgnoringWhiteSpace() {
        assertThat("aaaaaa ", equalToIgnoringWhiteSpace(" aaaaaa"));
    }
containsString
   /**
     * containsString, endsWith, startsWith - 測(cè)試字符串匹配
     */
    @Test
    public void hamcrestContainsString() {

        assertThat("abc", containsString("b"));
    }
is
   /**
     * 提高可讀性
     */
    @Test
    public void hamcrestIs() {
        assertThat("aaaa", is("bbbb"));
    }
isIn
    @Test
    public void hamcrestIsIn() {
        List<String> strings = Arrays.asList("aaa", "bbb");
        assertThat("aaa", isIn(strings));
    }

Mockito

官方示例 http://static.javadoc.io/org.mockito/mockito-core/2.20.0/org/mockito/Mockito.html

示例

class Car {
    String type;
    String code;

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getCarString(String year, String day) {

        return type + code + "_" + year + day;
    }
}

public class MockitoTest {

    Car car;

    @Before
    public void beforeTest() {
        car = mock(Car.class);
    }
}
mock
/**
 * mock類是不具有真實(shí)類的方法實(shí)現(xiàn)的
 */
@Test
public void mockObject() {

    Car car = mock(Car.class);
    System.out.println(car.getCarString("2222" ,null));

}
when
/**
     * OngoingStubbing<T> when(T methodCall)
     * <p>
     * OngoingStubbing: thenReturn揽惹、thenThrow、thenCallRealMethod四康、thenAnswer搪搏、getMock
     * <p>
     * 多個(gè)thenReturn會(huì)按調(diào)動(dòng)順序依次返回,直到最后
     */
    @Test
    public void mockWhen() {
        when(car.getCode()).thenReturn("111").thenReturn("2222");
        System.out.println(car.getCode());
        System.out.println(car.getCode());
        System.out.println(car.getCode());
    }
thenAnswer
   /**
     * thenAnswer可以接收傳入的參數(shù),自定義方法返回
     * ArgumentMatchers: anyString()
     */
    @Test
    public void mockThenAnswer() {
        when(car.getCarString(anyString(), anyString())).thenAnswer(invocation -> {

            System.out.println(invocation.getArgument(0) + "_" + invocation.getArgument(1));

            return "456789";
        });
        System.out.println(car.getCarString("11", "333"));
    }
verify
   /**
     * verify(T mock, VerificationMode mode)
     * <p>
     * VerificationMode 構(gòu)造 times(2), atLeastOnce(), atLeast(), atMost(), only(), never(), atLeastOnce(), description()
     */
    @Test
    public void mockVerify() {

        verify(car, times(2).description("get Code not appear 2 times")).getCode();

    }
reset
   /**
     * 重置
     */
    @Test
    public void mockReset() {
        when(car.getCode()).thenReturn("aaaa");
        System.out.println(car.getCode());
        reset(car);
        System.out.println(car.getCode());

    }
spy
/**
 * 監(jiān)控真實(shí)類闪金,使用do-when創(chuàng)建mock
 *
 */
@Test
public void spyObject() {
    Car carReal = new Car();
    Car spyCar = spy(carReal);
    System.out.println(spyCar.getCarString(null, null));
}
doThrow
/**
 * want void method throws Exception
 * doThrow可以添加多個(gè)Exception被依次調(diào)動(dòng)疯溺,直到最后一個(gè)
 */
@Test
public void mockDoThrow() {

    doThrow(new RuntimeException("first"), new RuntimeException("second")).when(car).setCode(anyString());

    try {
        car.setCode("aaa");
    } catch (Exception e) {
        System.out.println(e.getMessage());
    }
    try {
        car.setCode("bbb");
    } catch (Exception e) {
        System.out.println(e.getMessage());
    }
    try {
        car.setCode("ccc");
    } catch (Exception e) {
        System.out.println(e.getMessage());
    }
}
doCallRealMethod
   /**
     * 調(diào)用原始的方法實(shí)現(xiàn)
     */
    @Test
    public void mockDoCallRealMethod() {

        when(car.getCode()).thenReturn("bbbb");
        System.out.println(car.getCode());

        doCallRealMethod().when(car).getCode();
        System.out.println(car.getCode());

    }
doAnswer
    /**
     * void method 提供一個(gè)接收參數(shù)的自定義方法
     */
    @Test
    public void mockDoAnswer() {
        doAnswer(invocation -> null).when(car).setCode(anyString());
        car.setCode("3333");
    }
doNothing
   /**
     * void method 不做任何操作
     */
    @Test
    public void mockDoNothing() {
        doNothing().doThrow(new RuntimeException()).when(car).setType(anyString());

        car.setType("333");
        car.setType("4444");
    }
spy mock數(shù)據(jù)
   /**
     * 使用spy來監(jiān)控真實(shí)的對(duì)象,需要注意的是此時(shí)我們需要謹(jǐn)慎的使用when-then語句哎垦,而改用do-when語句
     */
    @Test
    public void mockDoReturn() {
        Car carReal = new Car();
        Car spyCar = spy(carReal);
        doReturn("spy object call mock data").when(spyCar).getCode();
        System.out.println(spyCar.getCode());
    }

PowerMock

不支持junit 5
需要依賴EasyMock或者M(jìn)ockito
最高支持到 Mockito 2.8.9(spring boot 2.0.4.RELEASE 中使用的Mockito版本為2.15)

PowerMock依賴Mockito版本

PowerMock version Mockito version
1.7.x 2.8.0 - 2.8.9
1.7.0RC4 2.7.5
1.7.0RC2 2.4.0
1.6.5 - 1.7.0RC 2.0.0-beta - 2.0.42-beta
1.6.2 - 2.0 1.10.8 - 1.10.x
1.5.0 - 1.5.6 1.9.5-rc1 - 1.9.5
1.4.10 - 1.4.12 1.9.0-rc1囱嫩、1.9.0
1.3.9 - 1.4.9 1.8.5
1.3.7、1.3.8 1.8.4
1.3.6 1.8.3
1.3.5 1.8.1漏设、1.8.2
1.3 1.8
1.2.5 1.7

pom依賴

    <dependency>
        <groupId>org.powermock</groupId>
        <artifactId>powermock-api-mockito2</artifactId>
        <version>1.7.4</version>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.powermock</groupId>
        <artifactId>powermock-module-junit4</artifactId>
        <version>1.7.4</version>
        <scope>test</scope>
    </dependency>

如果使用spring boot 2.0.0墨闲,則需要將spring boot test中的mockito依賴去掉,重新添加mockito 2.8.9

   <dependency>
       <groupId>org.mockito</groupId>
       <artifactId>mockito-core</artifactId>
       <version>2.8.9</version>
   </dependency>
   <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-test</artifactId>
       <scope>test</scope>
       <exclusions>
           <exclusion>
               <groupId>org.mockito</groupId>
               <artifactId>mockito-core</artifactId>
           </exclusion>
       </exclusions>
   </dependency>

依賴注解

@RunWith(PowerMockRunner.class)
@PrepareForTest({xx.class})

示例

public class Target {

    private String parameter;

    public Target() {
    }

    public Target(String parameter) {
        this.parameter = parameter;
    }

    public String getParameter() {
        return parameter;
    }


    private String privateMethod() {

        return "";
    }

    public String privateMethodWithParam(String str) {
        return "";
    }


    public String callPricateMethod() {
        return privateMethod();
    }

    public String callPricateMethodWithParam() {
        return privateMethodWithParam("");
    }

    public static String staticMethod() {

        return "";
    }
}


public final class FinalTarget {

    public final String print() {
        return "";
    }
}
PowermockTest static方法郑口、private方法鸳碧、construct方法

添加注解
@RunWith(PowerMockRunner.class)
@PrepareForTest({Target.class})
public class PowermockTest {}

static method
/**
 * mock 靜態(tài)方法
 *
 */
@Test
public void staticMock() {
    mockStatic(Target.class);
    when(Target.staticMethod()).thenReturn("static method mock data");
    System.out.println(Target.staticMethod());
}
pricate method
/**
 * mock private方法
 *
 * @throws Exception
 */
@Test
public void privateMock() throws Exception {
    Target target = new Target();
    Target targetSpy = spy(target);

    when(targetSpy, "privateMethod").thenReturn("private method mock deta");
    System.out.println(targetSpy.callPricateMethod());
}

/**
* mock 有入?yún)rivate方法
*
* @throws Exception
*/
@Test
public void privateMockWhithParam() throws Exception {
   Target targetSpy = spy(new Target());
   when(targetSpy, "privateMethodWithParam", anyString()).thenReturn("private method where parameter mock data");
   System.out.println(targetSpy.callPricateMethodWithParam());
}


/**
 * stub 方式 mock private方法
 *
 */
@Test
public void privateStubMock() {
    Target targetSpy = spy(new Target());
    stub(MemberMatcher.method(Target.class, "privateMethod")).toReturn("privvate method stub mock data");
    System.out.println(targetSpy.callPricateMethod());
}
construct method
/**
 * mock 構(gòu)造函數(shù)
 *
 * @throws Exception
 */
@Test
public void constructMock() throws Exception {

    Target mockTarget = new Target("mock data");

//    whenNew(Target.class).withNoArguments().thenReturn(new Target("mock data"));  不可以這么寫
    whenNew(Target.class).withNoArguments().thenReturn(mockTarget);

    Target target = new Target();

    System.out.println(target.getParameter());
} 

spring boot test

spring-boot-starter-test 添加的maven引用

JUnit — The de-facto standard for unit testing Java applications.
Spring Test & Spring Boot Test — Utilities and integration test support for Spring Boot applications.
AssertJ — A fluent assertion library.
Hamcrest — A library of matcher objects (also known as constraints or predicates).
Mockito — A Java mocking framework.
JSONassert — An assertion library for JSON.
JsonPath — XPath for JSON.

spring boot test 注解

基本注解 (類注解)

@SpringBootTest() 創(chuàng)建springApplication上下文盾鳞,支持SpringBoot特性(自動(dòng)配置

  • 參數(shù)class = ? 啟動(dòng)的配置類 (沒有默認(rèn)值杆兵,必須指定)
  • 參數(shù)webEnvironment = 雁仲?
    • Mock(<font color='grey'>默認(rèn)值</font>): 加載WebApplicationContext并提供Mock Servlet環(huán)境
    • RANDOOM_PORT: 加載EmbeddedWebApplicationContext并提供servlet環(huán)境,內(nèi)嵌服務(wù)的監(jiān)聽端口是隨機(jī)的
    • DEFINED_PORT: 加載EmbeddedWebApplicationContext并提供servlet環(huán)境琐脏,內(nèi)容服務(wù)的監(jiān)聽端口是定義好的。默認(rèn)端口是8080
    • NONE: 加載ApplicationContext缸兔,啟動(dòng)SpringApplication時(shí)日裙,不支持Servlet環(huán)境

@RunWith(SpringRun.class) 運(yùn)行Junit并支持Spring-test特性

@TestConfiguration 單元測(cè)試類使用的配置標(biāo)簽,沒有強(qiáng)制要求

spring mvc注解(類注解)

@WebMvcTest 自動(dòng)加載Spring MVC配置惰蜜、MockMvc配置昂拂、并掃描注解類

注:在沒有@WebMvcTest注解時(shí),使用@AutoConfiureMockMvc可以自動(dòng)配置MockMvc;@Component將不被掃描

mock bean注解 (成員變量 和 方法 注解抛猖,可以在配置文件中提供bean)

@MockBean 聲明需要模擬的服務(wù)

@SpyBean 定制化需要模擬服務(wù)的某個(gè)方法格侯,即部分方法可以mock,部分方法可以調(diào)用真實(shí)方法

事務(wù)回滾 (類 和 方法 注解)

@Transactional 開啟事務(wù)财著,回滾測(cè)試方法對(duì)數(shù)據(jù)庫(kù)的改變

對(duì)外接口文檔(類注解)

@AutoConfigureRestDocs

示例

Base Test
@RunWith(SpringRunner.class)
@SpringBootTest(classes = JunitDemoApplication.class)
@Import(TestConfig.class)
@Log
public class BootTest {

    @Autowired
    TestBean testBean;

    @Test
    public void bootTest() {
        log.info("boot test success");
        testBean.print();
    }


}
Mock Bean Test
@RunWith(SpringRunner.class)
@SpringBootTest(classes = JunitDemoApplication.class)
@Log
public class MockBeanTest{

    @MockBean
    RemoteDubboService remoteDubboService;

    @Autowired
    LocalService localService;


    @Before
    public void init() {
        log.info("mock bean before");
        when(remoteDubboService.getMsg()).thenReturn("mock remote dubbo Service");
    }

    @Test
    public void mockBean() {
        log.info("mock bean");

        localService.localPrint();
    }
}
Spy Bean Test
@RunWith(SpringRunner.class)
@SpringBootTest(classes = JunitDemoApplication.class)
@Log
public class SpyBeanTest{

    @SpyBean
    LocalSpyService localSpyService;

    @Before
    public void init() {
        doReturn("mock local spy out").when(localSpyService).out();
    }

    @Test
    public void spyTest() {
        log.info("syp bean");
        log.info(localSpyService.in());
        log.info(localSpyService.out());
    }
}
Spring MVC Test
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = JunitDemoApplication.class)
@WebMvcTest(MVCTest.class)
@Import(MybatisConfig.class)
@AutoConfigureRestDocs
@Log
public class SpringMVCTest {

    @Autowired
    MockMvc mockMvc;

    @Test
    public void mvcTest() throws Exception {

        this.mockMvc.perform(get("/mvc/enter").accept(MediaType.ALL))
                .andExpect(status().isOk())
                .andDo((document("mvcTest", responseFields(fieldWithPath("name").description("合同地址")))));
    }

}
Transactional Roll Back Test
@RunWith(SpringRunner.class)
@SpringBootTest(classes = JunitDemoApplication.class)
public class TransactionalRollBack{

    @Autowired
    MapperTest mapperTest;

    @Test
    @Transactional(timeout = 100)
    public void save() {
        mapperTest.save("12345678");
    }

}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末联四,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子撑教,更是在濱河造成了極大的恐慌朝墩,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,222評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件伟姐,死亡現(xiàn)場(chǎng)離奇詭異收苏,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)愤兵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,455評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門鹿霸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人秆乳,你說我怎么就攤上這事懦鼠。” “怎么了矫夷?”我有些...
    開封第一講書人閱讀 157,720評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵葛闷,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我双藕,道長(zhǎng)淑趾,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,568評(píng)論 1 284
  • 正文 為了忘掉前任忧陪,我火速辦了婚禮扣泊,結(jié)果婚禮上近范,老公的妹妹穿的比我還像新娘。我一直安慰自己延蟹,他們只是感情好评矩,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,696評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著阱飘,像睡著了一般斥杜。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上沥匈,一...
    開封第一講書人閱讀 49,879評(píng)論 1 290
  • 那天蔗喂,我揣著相機(jī)與錄音,去河邊找鬼高帖。 笑死缰儿,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的散址。 我是一名探鬼主播乖阵,決...
    沈念sama閱讀 39,028評(píng)論 3 409
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼预麸!你這毒婦竟也來了瞪浸?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,773評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤师崎,失蹤者是張志新(化名)和其女友劉穎默终,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體犁罩,經(jīng)...
    沈念sama閱讀 44,220評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡齐蔽,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,550評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了床估。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片含滴。...
    茶點(diǎn)故事閱讀 38,697評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖丐巫,靈堂內(nèi)的尸體忽然破棺而出谈况,到底是詐尸還是另有隱情,我是刑警寧澤递胧,帶...
    沈念sama閱讀 34,360評(píng)論 4 332
  • 正文 年R本政府宣布碑韵,位于F島的核電站,受9級(jí)特大地震影響缎脾,放射性物質(zhì)發(fā)生泄漏祝闻。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,002評(píng)論 3 315
  • 文/蒙蒙 一遗菠、第九天 我趴在偏房一處隱蔽的房頂上張望联喘。 院中可真熱鬧华蜒,春花似錦、人聲如沸豁遭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,782評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蓖谢。三九已至捂蕴,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間闪幽,已是汗流浹背启绰。 一陣腳步聲響...
    開封第一講書人閱讀 32,010評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留沟使,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,433評(píng)論 2 360
  • 正文 我出身青樓渊跋,卻偏偏與公主長(zhǎng)得像腊嗡,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子拾酝,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,587評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容

  • 海之魂_54ee閱讀 156評(píng)論 0 0
  • 四字訣“短燕少,流,少蒿囤,改”客们。 短:供應(yīng)鏈改善總體圍繞核心目標(biāo)從訂單到交付時(shí)間短,從訂單到現(xiàn)金時(shí)間短材诽,通過分解供應(yīng)鏈流...
    王亁坤閱讀 578評(píng)論 0 0
  • 我們的意識(shí)就像個(gè)儲(chǔ)存了成千上萬意識(shí)銘印的倉(cāng)庫(kù)底挫。它們就像機(jī)場(chǎng)跑道上的飛機(jī)一樣排著隊(duì)等待起飛。較強(qiáng)的銘印——根據(jù)我們此...
    柔光寶寶閱讀 185評(píng)論 0 0
  • 前言:NSURLConnection雖然已經(jīng)廢棄多年但是不能否定的是它帶我從iOS的UI編程升級(jí)到了iOS的網(wǎng)絡(luò)編...
    小苗曉雪閱讀 204評(píng)論 0 1
  • 1 生命中: 有多少人官边, 從相識(shí)相知到只剩一個(gè)姓名; 有多少愛外遇, 從海誓山盟到徒留一段曾經(jīng)注簿; 有多少情, 從相濡以...
    最熱話題精選閱讀 3,236評(píng)論 0 49