zoukankan      html  css  js  c++  java
  • Springboot 单元测试简单介绍和启动所有测试类的方法

    最近一段时间都是在补之前的技术债,一直忙着写业务代码没有注重代码的质量,leader也在强求,所有要把单元测试搞起来了

    我把单元测试分为两种 一个是service的单元测试,一个是controller层的单元测试接;

    单元测试肯定要引入单元测试包maven依赖

      <dependency>
                <groupId>org.junit.jupiter</groupId>
                <artifactId>junit-jupiter-api</artifactId>
                <version>RELEASE</version>
                <exclusions>
                    <exclusion>
                        <artifactId>opentest4j</artifactId>
                        <groupId>org.opentest4j</groupId>
                    </exclusion>
                </exclusions>
            </dependency>
     <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
    

      

    在介绍两个单元测试之前说一说我们一般写单元测试是不是这样的

    比如只了解service单元测试而且测试代码是这样的

    @RunWith(SpringRunner.class)
    @SpringBootTest(classes = {NpmcsApplication.class})
    public class ResourceServiceTest {
    
        @Autowired
        private ResourceService resourceService;
    
    
    
        @Test
        public void countTotal() {
            Map<String, Object> map = resourceService.countTotal("2019-10-21", "2019-10-25");
            System.out.printl(map);
        }
    }

    都是传入条件直接输出当然并不能说这种不能达到测试的效果,但是我们是追求完美的coder要追求性能和代码的美观 System.out是分非常的消耗性能的,既然是单元测试肯定要有断言,这个应该都听过

    测试包下面有断言的方法提供了很多

     这里有很多的断言方法比如上面的代代码可以修改为

    @RunWith(SpringRunner.class)
    @SpringBootTest(classes = {NpmcsApplication.class})
    public class ResourceServiceTest {
    
        @Autowired
        private ResourceService resourceService;
    
    
    
        @Test
        public void countTotal() {
            Map<String, Object> map = resourceService.countTotal("2019-10-21", "2019-10-25");
             Assert.assertNotNull(map);
     
        }
    }

    上面代码重点是, 测试类加@RunWith注解, 还有加上 @SpringBootTest(classes = App.class) 注解, 这里的 App.class 是主程序java类. 主程序java程序必须是SpringBootApplication程序, 否则测试用例会报如下错误:
    Unable to find a @SpringBootConfiguration, you need to use @ContextConfiguration or @SpringBootTest(classes=...) with your test java.lang.IllegalStateException.

    @RunWith是JUnit的一个注解, 用来告诉JUnit不要使用内置的方式进行单元测试, 而应该使用指定的类做单元测试 对于Spring单元测试总是要使用 SpringRunner.class . 

    @SpringBootTest 用来指定SpringBoot应用程序的入口类, 该注解默认会根据包名逐级往上找, 一直找到一个SpringBoot主程序class为止, 然后启动该类为单元测试准备Spring上下文环境.  Spring单元测试并不在每个测试方法前都移动一个全新的Spring上下文, 因为这样做太耗费时间, 而是会缓存上下文环境. 如果某个测试方法需要重新准备Spring上下文, 需要在该方法上加 @DirtiesContext 注解. 

    @Test注解: JUnit在执行每个测试方法之前, 都会为测试类创建一个新的实例, 这样有助于隔离各个测试方法之前的相互影响. 

    接下来说一下controller测试这个有点复杂用到的MockMvc,针对API测试的一个库

    话不多说直接刚代码

    @RunWith(SpringJUnit4ClassRunner.class)
    @SpringBootTest
    public class PressureViewContorllerTest {
        @Autowired
        private WebApplicationContext context;
        private MockMvc mockMvc;
        private MockHttpSession session;
    
        @Before
        public void before() throws Exception {
            mockMvc = MockMvcBuilders.webAppContextSetup(this.context).build();
            session = new MockHttpSession();
            User user = new User();
            user.setName("小明");
            session.setAttribute("user", user);
    
        }
    
        @After
        public void after() throws Exception {
    
        }
    
        /**
         * Method: showPressure()
         */
        @Test
        public void testShowPressure() throws Exception {
            String json = "{
    " + "	"startDate": "2019-09-14",
    " + "	"endDate": "2019-10-14"
    " + "}";
            MultiValueMap<String, String> params = new LinkedMultiValueMap<String, String>();
            params.add("startDate", "2019-09-14");
            params.add("endDate", "2019-10-14");
    
            RequestBuilder request =
                    MockMvcRequestBuilders.post("/pressure/pressureView").contentType(MediaType.APPLICATION_JSON)
                            .params(params);
            MvcResult mvcResult = mockMvc.perform(request).andExpect(MockMvcResultMatchers.status().isOk()).andDo(
                    MockMvcResultHandlers.print()).andReturn();
    
            int status = mvcResult.getResponse().getStatus();
    
            String content = mvcResult.getResponse().getContentAsString();
            Assert.assertTrue("正确", status == 200);
            Assert.assertFalse("错误", status != 200);
        }
    
        /**
         * Method: pressureList()
         */
        @Test
        public void testPressureList() throws Exception {
            MultiValueMap<String, String> params = new LinkedMultiValueMap<String, String>();
            params.add("startDate", "2019-09-14");
            params.add("endDate", "2019-10-14");
            RequestBuilder request =
                    MockMvcRequestBuilders.post("/pressure/list").contentType(MediaType.APPLICATION_JSON_UTF8)
                            .params(params);
            MvcResult mvcResult = mockMvc.perform(request).andExpect(MockMvcResultMatchers.status().isOk()).andDo(
                    MockMvcResultHandlers.print()).andReturn();
    
            int status = mvcResult.getResponse().getStatus();
            String content = mvcResult.getResponse().getContentAsString();
            Assert.assertTrue("正确", status == 200);
            Assert.assertFalse("错误", status != 200);
        }
    
    
    
    
    } 

    代代码讲解:

    首先要注入MockMvc  ,MockHttpSession ,WebApplicationContext  初始化这些对象@Before这个方法是在每个Test方法之前执行,模拟登录因为登录拦截检测是否有session信息

     mockMvc.perform() 模仿页面调用接口 MockMvcRequestBuilders.post("/pressure/list") 这个是掉POST方法 GET直接.get(url) 

    MultiValueMap<String, String> params = new LinkedMultiValueMap<String, String>();

     params.add("startDate", "2019-09-14");

    params.add("endDate", "2019-10-14");

    这个是模拟参数 使用的是 MockMvcRequestBuilders.post("/pressure/list").contentType(MediaType.APPLICATION_JSON_UTF8) .params(params);

    也可以使用

            mvc.perform(MockMvcRequestBuilders.get("/manPower/countManPowerByTeam").param("startDate","2019-01-01").param("endDate","2019-12-31")).andExpect(MockMvcResultMatchers.status().isOk()).andDo(MockMvcResultHandlers.print()).andReturn();
    这段代码:
    mockMvc.perform(request).andExpect(MockMvcResultMatchers.status().isOk()).andDo(
                    MockMvcResultHandlers.print()).andReturn();

    期望返回status是ok 并且打印放回的结果

    最后附上启动所有的测试类方法使用的是TestSuite

    /**
     * 启动所有的测试类
     * @Author zly
     * @Date 2018/11/2 09:54
     */
    @RunWith(Suite.class)
    @Suite.SuiteClasses({TeamServiceTest.class,
            PressureViewContorllerTest.class,
            UserControllerTest.class,
            FlowViewControllerTest.class,
            HttpConnUtilTest.class, DemandPICControllerTest.class, DemandProtraitServiceTest.class})
    public class TestSuite {

    就是把所有的测试类注入进来

    有写的不好之处希望各路大佬指教 共同成长

  • 相关阅读:
    可执行程序的装载
    stdafx.h的作用
    AI调色板
    3ds max输出图片
    3ds max移除几何体的线段
    3ds max删除了对象后,还是将原来所有对象输出的原因
    vs win32 & MFC 指针默认位置
    3ds max 分离对象
    PDF
    endnote设置文献第二行悬挂缩进办法
  • 原文地址:https://www.cnblogs.com/blackCatFish/p/12156552.html
Copyright © 2011-2022 走看看