springboot test

前言

mac上idea快捷鍵,command+shift+T根據(jù)類生成快捷鍵。

對spring容器中的類做單元測試

在src/main下建立UserService類,對其進(jìn)行單于測試,生產(chǎn)其單元測試類(使用command+shift+T快捷鍵),生成的test類在src/test下

@Service
public class UserService {

    public Integer addUser(String username){
        System.out.println("user dao adduser [username="+username+"]");
        if(username == null){
            return 0;
        }
        return 1;
    }
}

springboot啟動(dòng)類:

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class,args);
    }
}

測試類:

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserServiceTest {

    @Autowired
    private UserService userService;

    @Test
    public void addUser() throws Exception {
        Assert.assertEquals(Integer.valueOf(1),userService.addUser("zhihao.miao"));
        Assert.assertEquals(Integer.valueOf(0),userService.addUser(null));
    }

}

盲點(diǎn)掃描

RunWith注解,SpringRunner類,SpringJUnit4ClassRunner類,SpringBootTest注解的解釋。

RunWith注解

When a class is annotated with @RunWith or extends a class annotated with @RunWith, JUnit will invoke the class it references to run the tests in that class instead of the runner built into JUnit. We added this feature late in development. While it seems powerful we expect the runner API to change as we learn how people really use it. Some of the classes that are currently internal will likely be refined and become public.
當(dāng)一個(gè)類用@RunWith注釋或繼承一個(gè)用@RunWith注釋的類時(shí),JUnit將調(diào)用它所引用的類來運(yùn)行該類中的測試而不是開發(fā)者去在junit內(nèi)部去構(gòu)建它。我們在開發(fā)過程中使用這個(gè)特性。

For example, suites in JUnit 4 are built using RunWith, and a custom runner named Suite:
比如說,suites使用RunWith注解構(gòu)建,

@RunWith(Suite.class)
@SuiteClasses({ATest.class, BTest.class, CTest.class})
public class ABCSuite {
}
SpringRunner注解

SpringRunner is an alias for the SpringJUnit4ClassRunner.
SpringRunnerSpringJUnit4ClassRunner的一個(gè)別名。

To use this class, simply annotate a JUnit 4 based test class with @RunWith(SpringRunner.class).
使用這個(gè)類,簡單注解一個(gè)JUnit 4 依賴的測試@RunWith(SpringRunner.class).

If you would like to use the Spring TestContext Framework with a runner other than
this one, use org.springframework.test.context.junit4.rules.SpringClassRule
and org.springframework.test.context.junit4.rules.SpringMethodRule.
如果你想使用Spring測試上下文而不是使用這個(gè),你可以使用org.springframework.test.context.junit4.rules.SpringClassRuleorg.springframework.test.context.junit4.rules.SpringMethodRule.

SpringJUnit4ClassRunner

SpringJUnit4ClassRunner is a custom extension of JUnit's
BlockJUnit4ClassRunner which provides functionality of the
Spring TestContext Framework to standard JUnit tests by means of the
TestContextManager and associated support classes and annotations.
SpringJUnit4ClassRunner是JUnit's的BlockJUnit4ClassRunner類的一個(gè)常規(guī)擴(kuò)展,提供了一些spring測試環(huán)境上下文去規(guī)范JUnit測試,意味著TestContextManager和支持相關(guān)的類和注解。

SpringBootTest注解

Annotation that can be specified on a test class that runs Spring Boot based tests.
Provides the following features over and above the regular Spring TestContext
Framework:
注解制定了一個(gè)測試類運(yùn)行了Spring Boot環(huán)境。提供了以下一些特性:

Uses SpringBootContextLoader as the default ContextLoader when no specific ContextConfiguration#loader() @ContextConfiguration(loader=...) is defined.
當(dāng)沒有特定的ContextConfiguration#loader()(@ContextConfiguration(loader=...))被定義那么就是SpringBootContextLoader作為默認(rèn)的ContextLoader。

Automatically searches for a SpringBootConfiguration @SpringBootConfiguration when nested @Configuration is not used, and no explicit #classes() classes are
specified.
自動(dòng)搜索到SpringBootConfiguration注解的文件。

Allows custom Environment properties to be defined using the properties() properties attribute}.
允許自動(dòng)注入Environment類讀取配置文件。

Provides support for different #webEnvironment() webEnvironment modes,
including the ability to start a fully running container listening on a
WebEnvironment#DEFINED_PORT defined or WebEnvironment#RANDOM_PORT
random port.
提供一個(gè)webEnvironment環(huán)境,可以完整的允許一個(gè)web環(huán)境使用隨機(jī)的端口或者自定義的端口。

Registers a org.springframework.boot.test.web.client.TestRestTemplate
TestRestTemplate bean for use in web tests that are using a fully running container.
注冊了TestRestTemplate類可以去做接口調(diào)用。

springboot測試步驟

  • 直接在測試類上面加上如下2個(gè)注解
    @RunWith(SpringRunner.class)
    @SpringBootTest
    就能取到spring中的容器的實(shí)例,如果配置了@Autowired那么就自動(dòng)將對象注入。

在測試環(huán)境中獲取一個(gè)bean,在項(xiàng)目中新建User類,然后在測試模塊進(jìn)行測試

在src/main下新建一個(gè)實(shí)例User

@Component
public class User {
}

src/test下創(chuàng)建測試類測試:

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserTest {


    @Autowired
    public ApplicationContext context;

    @Test
    public void testNotNull(){
        Assert.assertNotNull(context.getBean(User.class));
    }
}

只在測試環(huán)境有效的bean

在src/test下新建二個(gè)類,我們發(fā)現(xiàn)分別使用@TestComponent和@TestConfiguration二個(gè)注解修飾,這些類只在測試環(huán)境生效

@TestComponent
public class Cat {

    public void index(){
        System.out.println("cat index");
    }
}
@TestConfiguration
public class TestBeanConfiguration {

    @Bean
    public Runnable createRunnable(){
        return () -> System.out.println("=====createRunnable=======");
    }
}

測試類:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = {TestBeanConfiguration.class,Cat.class})
public class TestApplication {

    @Autowired
    public ApplicationContext context;

    @Test
    public void testNotNull(){
        Runnable runnable = context.getBean(Runnable.class);
        runnable.run();
        System.out.println("--------");

        Cat cat = context.getBean(Cat.class);
        cat.index();
    }
}

需要在@SpringBootTest注解的參數(shù)classes中加入?yún)?shù),表示將某些類納入測試環(huán)境的容器中。

TestComponent注解
TestConfiguration注解

配置文件屬性的讀取

springboot會只會讀取到src/test/resources下的配置,不會讀到正式環(huán)境下的配置文件(跟以前1.4.*版本的不一樣,以前是優(yōu)先讀取測試環(huán)境配置文件,然后讀取正式環(huán)境的配置)

@RunWith(SpringRunner.class)
@SpringBootTest
public class EnvTest {

    @Autowired
    public Environment environment;

    @Test
    public void testValue(){
        Assert.assertEquals("zhihao.miao",environment.getProperty("developer.name"));

    }
}

除了在配置文件中設(shè)置屬性,測試環(huán)境加載一些配置信息的二種方式:
第一種是使用@SpringBootTest注解,注解參數(shù)properties指定其value值,第二種使用EnvironmentTestUtils.addEnvironment方法進(jìn)行設(shè)置。
測試:

@RunWith(SpringRunner.class)
@SpringBootTest(properties = {"app.version=1.0"})
public class EnvTest2 {

    @Autowired
    private ConfigurableEnvironment environment;

    @Before
    public void init(){
        EnvironmentTestUtils.addEnvironment(environment,"app.admin.user=zhangsan");
    }

    @Test
    public void testApplication(){
        Assert.assertEquals("1.0",environment.getProperty("app.version"));
        Assert.assertEquals("zhangsan",environment.getProperty("app.admin.user"));
    }
}

Mock方式的測試

正式環(huán)境只是一個(gè)接口,并沒有實(shí)現(xiàn),也并沒有納入spring容器進(jìn)行管理。

public interface UserDao {
    Integer createUser(String userName);
}

測試

@RunWith(SpringRunner.class)
public class UserDaoTest {

    //使用MockBean是因?yàn)榇藭r(shí)容器中沒有UserMapper這個(gè)對象
    @MockBean
    public UserDao userDao;

    //使用BDDMockito對行為進(jìn)行預(yù)測,
    @Before
    public void init(){
        BDDMockito.given(userDao.createUser("admin")).willReturn(1);
        BDDMockito.given(userDao.createUser("")).willReturn(0);
        BDDMockito.given(userDao.createUser(null)).willThrow(NullPointerException.class);
    }

    @Test(expected=NullPointerException.class)
    public void testCreateUser() {
        Assert.assertEquals(Integer.valueOf(1),userDao.createUser("admin")) ;
        Assert.assertEquals(Integer.valueOf(0),userDao.createUser("")) ;
        Assert.assertEquals(Integer.valueOf(1),userDao.createUser(null)) ;
    }
}

對controller進(jìn)行測試

第一種方式:
定義一個(gè)Controller,用作測試:

@RestController
public class UserController {

    private Logger logger = LoggerFactory.getLogger(getClass());

    @GetMapping("/user/home")
    public String home(){
        logger.info("user home");
        return "user home";
    }

    @GetMapping("/user/show")
    public String show(@RequestParam("id") String id){
        logger.info("book show");
        return "show"+id;
    }
}

使用瀏覽器訪問

http://localhost:8080/user/home
http://localhost:8080/user/show?id=100

使用測試類測試

@RunWith(SpringRunner.class)
//指定web環(huán)境,隨機(jī)端口
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class UserControllerTest {

    //這個(gè)對象是運(yùn)行在web環(huán)境的時(shí)候加載到spring容器中
    @Autowired
    private TestRestTemplate testRestTemplate;

    @Test
    public void testHome(){
        String context = testRestTemplate.getForObject("/user/home",String.class);
        Assert.assertEquals("user home",context);
    }

    @Test
    public void testShow(){
        String context = testRestTemplate.getForObject("/user/show?id=100",String.class);
        Assert.assertEquals("show10",context);
    }
}

第二種方式,使用@WebMvcTest注解

@RunWith(SpringRunner.class)
@WebMvcTest(controllers = UserController.class)
public class UserControllerTest2 {

    @Autowired
    public MockMvc mockMvc;

    @Test
    public void testHome() throws Exception {
        mockMvc.perform(MockMvcRequestBuilders.get("/user/home")).andExpect(MockMvcResultMatchers.status().isOk());
        mockMvc.perform(MockMvcRequestBuilders.get("/user/home")).andExpect(MockMvcResultMatchers.status().isOk()).andExpect(MockMvcResultMatchers.content().string("user home"));
    }

    @Test
    public void testShow() throws Exception {
        mockMvc.perform(MockMvcRequestBuilders.get("/user/show").param("id", "400")).andExpect(MockMvcResultMatchers.status().isOk());
        mockMvc.perform(MockMvcRequestBuilders.get("/user/show").param("id", "400")).andExpect(MockMvcResultMatchers.status().isOk()).andExpect(MockMvcResultMatchers.content().string("show400"));
    }
}
WebMvcTest

@WebMvcTest 不需要運(yùn)行在web環(huán)境下,但是,需要指定controllers,表示需要測試哪些controllers。
這種方式只測試controller,controller里面的一些依賴,需要你自己去mock
@WebMvcTest 不會加載整個(gè)spring容器。

第三種方式
使用@SpringBootTest()與@AutoConfigureMockMvc結(jié)合,@SpringBootTest使用@SpringBootTest加載測試的spring上下文環(huán)境,@AutoConfigureMockMvc自動(dòng)配置MockMvc這個(gè)類,

/**
 * @SpringBootTest 不能和  @WebMvcTest 同時(shí)使用
 * 如果使用MockMvc對象的話,需要另外加上@AutoConfigureMockMvc注解
 */
@RunWith(SpringRunner.class)
@SpringBootTest()
@AutoConfigureMockMvc
public class UserControllerTest3 {

    @Autowired
    private MockMvc mvc;

    @Test
    public void testHome() throws Exception {
        mvc.perform(MockMvcRequestBuilders.get("/user/home")).andExpect(MockMvcResultMatchers.status().isOk());
        mvc.perform(MockMvcRequestBuilders.get("/user/home")).andExpect(MockMvcResultMatchers.status().isOk()).andExpect(MockMvcResultMatchers.content().string("user home"));
    }

    @Test
    public void testShow() throws Exception {
        mvc.perform(MockMvcRequestBuilders.get("/user/show").param("id", "400")).andExpect(MockMvcResultMatchers.status().isOk());
        mvc.perform(MockMvcRequestBuilders.get("/user/show").param("id", "400")).andExpect(MockMvcResultMatchers.status().isOk()).andExpect(MockMvcResultMatchers.content().string("show400"));
    }
}

一個(gè)注解可以使測試類可以自動(dòng)配置MockMvc這個(gè)類。


AutoConfigureMockMvc注解
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,868評論 18 139
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,937評論 6 342
  • spring官方文檔:http://docs.spring.io/spring/docs/current/spri...
    牛馬風(fēng)情閱讀 1,721評論 0 3
  • Spring 技術(shù)筆記Day 1 預(yù)熱知識一、 基本術(shù)語Blob類型,二進(jìn)制對象Object Graph:對象圖...
    OchardBird閱讀 996評論 0 2
  • 周三了 眾所周知今日要結(jié)束 是啊 你與我們都不舍 我們的嘴角 我們的口輪匝肌 我們的笑肌 我們的皺眉肌 臉上所有的...
    樹的話閱讀 253評論 2 2