• 两个基于spring的单元测试简单样例


      单元测试,从一定程度上可以看出一个同学达到的层次。但又不完全是,有时可能只是一个思考方式的转变。单元测试有非常多的工具供选择,在java中,junit无疑是比较常用的。本文列出,junit在spring中的使用样例,供参考。

    1. 单元测试主要方式

      这里仅说我们常用的单元测试的场景,或者是我自己常用的场景,主要分为4大类:

        1. 对外提供的接口级别的测试,如rest-api, 主要用于保证对外提供的接口符合预期, 而非等到别人调用时才发现异常; 

        2. serivce 级别的单元测试, 主要用于保证service功能正常;

        3. 静态方法的测试, 主要用于测试一些工具类符合预期,这类测试一般比较简单;

        4. mock接口实现测试, 这类测试往往最复杂, 一般是为测试复杂场景, 但又要保证影响因素单一, 保证测试的有效性, 要求既要mock得少也要求mock得合适, 最难;

          一般还有对环境初始化时的运行,和结束测试时的清理工作,即setup() 和teardow(). 在junit中就体现为两个注解:@Before 和 @After 。

      实际上,除了最后一种测试是比较体系化和完备的之外,前几种也许都不是那么细致,至少一般测试不到某个很小的点上,或者说场景不一致。api,service一般会涉及到复杂的外部系统调用,一是依赖多二是速度慢,而尽量保持本地化测试中一个最佳实践。但记住一点,单元测试应该基于行为,而非基于实现。

    2. springmvc 的单元测试样例

      这里主要说的是低版本的springmvc, 里面依赖还比较原始, 所以需要单独讲讲。其依赖包可如下参考:

            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.12</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.hamcrest</groupId>
                <artifactId>hamcrest-core</artifactId>
                <version>1.3</version>
            </dependency>
            <dependency>
                <groupId>org.hamcrest</groupId>
                <artifactId>hamcrest-library</artifactId>
                <version>1.3</version>
            </dependency>
            <dependency>
                <groupId>org.mockito</groupId>
                <artifactId>mockito-all</artifactId>
                <version>1.9.5</version>
                <scope>test</scope>
            </dependency>

      测试用例样例如下:(主要注意必要时引用 servlet的配置就行,否则可能找不到对应的controller)

    @RunWith(SpringJUnit4ClassRunner.class)
    @WebAppConfiguration
    @ContextConfiguration({"classpath:applicationContext.xml",
                            "classpath:applicationContext-servlet.xml"})
    public class SpringMvcTest {
    
        @Autowired
        private WebApplicationContext wac;
    
        private MockMvc mockMvc;
    
        @Before
        public void before() throws Exception {
            mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
        }
    
        // 对外提供的接口级别的测试 @Before  @After
        @Test
        public void tesaDataAddKeyword() throws Exception {
            TestObj tobj;
            MvcResult mvcResult;
            String responseResult;
            JSONObject resultObj;
            tobj = new TestObj();
            tobj.setXX(302L);
            mvcResult = mockMvc.perform(
                    MockMvcRequestBuilders.post("/test/add")
                            .contentType("application/json")
                            .characterEncoding("utf-8")
                            .content(JSONObject.toJSONString(tobj)))
                    .andExpect(MockMvcResultMatchers.status().is(200))
                    .andReturn();
            responseResult = mvcResult.getResponse().getContentAsString();
            System.out.println("接口返回结果:" + responseResult);
            resultObj = JSONObject.parseObject(responseResult);
            Assert.assertNotNull("响应结果为空", resultObj);
            Assert.assertThat("正常插入失败",
                    resultObj.getInteger("status"), is(1));
    
        }
    
        
        @Resource
        private TestService testService;
        
        // serivce 级别的单元测试
        @Test
        public void testPureKeyword() {
            TestObj tObj = new TestObj();
            tObj.setXXX(302L);
            try {
                testService.checkKeyWord(tObj);
            }
            catch (BizException e) {
                Assert.assertEquals("错误码返回不正确", 4001021, e.getErrCode());
            }
        }
    
        // 静态方法的测试
        @Test
        public void testUiExtract() {
            String ruleEL;
            ParsedClause parsedClause;
    
            ruleEL = "ui_extract($123, 'md') = '02-01'";
    
            parsedClause = SyntaxParser.parse(ruleEL);
    
            Assert.assertEquals("数量解析不正确",
                    1, parsedClause.getLabelIdMapping().size());
            Assert.assertEquals("解析UPP结果不正确",
                    "string.substring($123 , 5, 10) = '02-01'",
                    parsedClause.translateTo(DialectTypeEnum.ES));
            Assert.assertEquals("解析结果不正确",
                    "substr($123 , 5, 5) = '02-01'",
                    parsedClause.translateTo(DialectTypeEnum.HIVE));
    
        }
    
        // mock接口实现测试
        @Test
        public void testMockInterface() {
    
            List mockList = Mockito.mock(List.class);
            mockList.add("1");
            // 返回null,说明并没有调用真正的方法
            Assert.assertNull("mock没有返回null", mockList.get(0));
            Mockito.when(mockList.size()).thenReturn(100);//stub
            // size() method was stubbed,返回100
            Assert.assertThat("mock.size未返回预期值",
                        mockList.size(), is(100));
    
            //test for Spy
            List list = new LinkedList();
            List spy = Mockito.spy(list);
    
            //optionally, you can stub out some methods:
            Mockito.when(spy.size()).thenReturn(100);
    
            //using the spy calls real methods
            spy.add("one");
            spy.add("two");
    
            //prints "one" - the first element of a list
            System.out.println(spy.get(0));
    
            //size() method was stubbed - 100 is printed
            System.out.println(spy.size());
        }
    
        // 预期发生异常的场景测试
        @Test(expected = BizException.class)
        public void testMethodThrow() {
            SyntaxParser.parse(null);
        }
    
    }

      即对上面4种场景的简单实现样例。

    3. springboot的单元测试样例

      springboot为我们省去了许多的依赖问题,所以不会很麻烦。只需引入 test 包,其他相应依赖就下来了。而且一般都是demo代码里默认带有的依赖:

            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
                <exclusions>
                    <exclusion>
                        <groupId>org.junit.vintage</groupId>
                        <artifactId>junit-vintage-engine</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>

      其使用样例则也会更简单,一个注解搞定了。

    @RunWith(SpringRunner.class)
    @SpringBootTest
    @AutoConfigureMockMvc
    public class DemoBatchDataControllerTest {
    
        @Autowired
        private MockMvc mockMvc;
    
        @Test
        public void testApi1() throws Exception {
            MvcResult result = mockMvc.perform(get("/demo/test1"))
                                .andExpect(status().isOk())
                                .andReturn();
            Assert.assertThat("结果不正确", 
                    result.getResponse().getContentAsString(), containsString("ok"));
        }
    
        // 其他同springmvc
    
    
    }

      可见springboot确实简单了许多。但框架始终只是框架,需要用户注入灵魂,才能在其上面玩出花样来。

    4. junit常用断言枚举

          测试有个非常重要的属性就是,有预期。当预期结果不一致时,则用例失败。即断言判定。种类实际也不多,罗列如下:

    // 断言两个对象是否相等
    assertEquals
    // 断言两个数组是否包含相同的元素
    assertArrayEquals
    // 断言语句为真
    assertTrue
    // 断言语句为假
    assertFalse
    // 断言对象引用为空
    assertNull
    // 断言对象引用不为空
    assertNotNull
    // 断言两个对象指向同一对象,即同对象
    assertSame
    // 断言两个对象不是指同一个
    assertNotSame
    // 断言对象满足某个条件(自定义实现,有部分现成工具类供调用)
    assertThat
    // 定义符合预期的异常
    @Test(expect = xxxException.class)
    

          基本上,通过以上断言,就可以将测试预判做好了。但也不那么简单。

      测试驱动或者测试先行开发,是一种比较好的实践,可以让我们少走弯路,且更自信。

    不要害怕今日的苦,你要相信明天,更苦!
  • 相关阅读:
    Sample XPS Documents Download
    触发器中的inserted表和deleted表
    Using freewheel.labs.autodesk.com to auto generate preview images of DWF files on your web site
    解除SQL对组件"Ad Hoc Distributed Queries"的"STATEMENT'OpenRowset OpenDatasource"的访问
    读写xps
    XPS文件,在Windows XP下的打开查看阅读和打印方法。
    Learning to Reference Inserted and Deleted Tables
    Get value from updated, inserted and deleted
    Reinstall Microsoft Helper Viewer
    如何查找文件的IFilter
  • 原文地址:https://www.cnblogs.com/yougewe/p/14540105.html
Copyright © 2020-2023  润新知