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

JAVA烂猪皮

共 6663字,需浏览 14分钟

 ·

2021-03-17 08:19

走过路过不要错过

点击蓝字关注我们


单元测试,从一定程度上可以看出一个同学达到的层次。但又不完全是,有时可能只是一个思考方式的转变。单元测试有非常多的工具供选择,在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@AutoConfigureMockMvcpublic 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确实简单了许多。但框架始终只是框架,需要用户注入灵魂,才能在其上面玩出花样来。  

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




往期精彩推荐



腾讯、阿里、滴滴后台面试题汇总总结 — (含答案)

面试:史上最全多线程面试题 !

最新阿里内推Java后端面试题

JVM难学?那是因为你没认真看完这篇文章


END


关注作者微信公众号 —《JAVA烂猪皮》


了解更多java后端架构知识以及最新面试宝典


你点的每个好看,我都认真当成了


看完本文记得给作者点赞+在看哦~~~大家的支持,是作者源源不断出文的动力


作者:等你归去来

出处:https://www.cnblogs.com/yougewe/p/14540105.html

浏览 38
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报