大家好,欢迎来到IT知识分享网。
单元测试对程序来说非常重要,它不仅能增强程序的健壮性,而且也为程序的重构提供了依据。目前很多开源项目的测试覆盖率都高达 90%以上,由此可见单元测试的重要性。
1,JUnit 5
1.1,基本概念
JUnit是用于Java的开源测试框架,能够帮助简化单元测试流程。传统的测试方式需要新建类和main()方法来编写测试代码,如果测试代码较多,会增加复杂度和降低测试积极性。而JUnit可以在编写代码的同时进行单元测试,帮助快速追踪问题原因,减小回归错误的难度。
- 单元测试:JUnit专注于单元测试,即测试代码中最小的可测试单元(通常是一个方法)。通过单元测试,开发者可以验证代码的正确性和稳定性。
- 注解:JUnit使用注解来标记测试方法和测试类。常用的注解有
@Test用于标记测试方法,@Before和@After用于在测试方法执行前后执行一次性的设置和清理操作,@BeforeClass和@AfterClass用于在测试类初始化前后执行一次性的设置和清理操作。- 断言:JUnit提供了一系列的断言方法,如
assertEquals、assertTrue、assertFalse等,用于验证测试结果和预期值是否一致。- 测试运行器:JUnit的测试运行器(Runner)用于执行测试,并提供不同的执行策略,比如顺序执行、并发执行等。JUnit 4之后,引入了
@RunWith注解用于指定测试运行器。- 测试套件:JUnit支持将多个测试类组合成一个测试套件,通过
@RunWith(Suite.class)注解可以运行套件中的所有测试类。- 异常测试:JUnit允许测试方法预期抛出特定的异常,并通过
@Test注解的expected属性指定预期异常。- 超时测试:JUnit允许设置测试方法的最大执行时间,超过该时间则标记为失败。
JUnit编写测试类原则:
- 测试方法上必须使用@Test进行修饰。
- 测试方法必须使用public void 进行修饰,不能带任何的参数。
- 新建一个源代码目录来存放我们的测试代码,即将测试代码和项目业务代码分开。
- 测试类所在的包名应该和被测试类所在的包名保持一致。
- 测试单元中的每个方法必须可以独立测试,测试方法间不能有任何的依赖。
- 测试类使用Test作为类名的后缀(不是必须)。
- 测试方法使用test作为方法名的前缀(不是必须)。
JUnit测试步骤:
- 在测试类中定义一个或多个测试方法,每个测试方法都使用@Test 修饰。如果要在测试方法执行之前调用某些方法来初始化资源,则使用@BeforeEach 修饰这些方法。如果要在测试方法执行之后调用某些方法 来回收资源,则使用@AfterEach 修饰这些方法。
- 在测试方法中调用 assertXxx 进行断言。早期版本的断言,通常就是断言被测试组件的某个方法的返回值与期望值相等;JUnit 5 则可断言被测试组件的某个方法不抛出异常,或者断言被测试组件的某个方法不会超时,或者断言可成功执行一个或多个 Lambda 表达式,等等。
【待测方法】
public class Calculator { public int add(int a, int b) { return a + b; } }【传统测试】
public class CalculatorTestMain { public static void main(String[] args) { Calculator calculator = new Calculator(); int result = calculator.add(1, 2); if (result == 3) { System.out.println("add()方法正确"); } else { System.out.println("add()方法错误"); } } }【JUnit测试】
<dependency> <groupId>org.junit.platform</groupId> <artifactId>junit-platform-launcher</artifactId> <version>1.7.0</version> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter</artifactId> <version>5.7.0</version> </dependency>public class CalculatorTestJUnit { @Test public void testAdd() { Calculator calculator = new Calculator(); int result = calculator.add(1, 2); //assertTequals:判断两个对象的值是否相等 //assertSame:内部使用==判断 Assert.assertEquals(result, 3); } }
1.2,JUnit注解
JUnit 5 常用注解:
- @BeforeAll:方法必须必须要是静态方法(static 声明),所有测试开始之前运行,同JUnit 4的@BeforeClass。
- @BeforeEach:每次运行测试方法前都先运行指定的初始方法,同JUnit 4的@Before。
- @Test(expected=XXException.class):测试方法,如果程序的异常和XXException.class一样,则测试通过。
- @Test(timeout=100):如果程序的执行能在100毫秒之内完成,则测试通过。
- @AfterEach:每次运行测试方法后都运行指定的回收资源方法,同JUnit 4的@Before。
- @AfterAll:方法必须要是静态方法(static 声明),所有测试结束之后运行,同JUnit 4的@AfterClass。
JUnit 5 其他注解:
- @Disabled:被忽略的测试方法,同JUnit 4的@Ignore。
- @ParameterizedTest:表示对方法执行参数化测试。
- @RepeatedTest:表示对方法执行重复测试。
- @DisplayName:表示为测试类或测试方法设置展示名称。
- @Tag:表示单元测试的标签,其大致等同于 Junit 4 中的@Category 注解。
- @Timeout:设置如果测试方法运行超过了指定时间,则将返回错误。
- @ExtendWith:为测试类或测试方法提供扩展类引用。
- @Nested:修饰内部测试类。
1.3,Assertions
Assertions类是一系列断言方法的集合。Assertions 类包含了一组静态的断言方法,用于比较期望值和实际值是否匹配,如果匹配,则表明测试通过;否则算测试失败,JUnit 测试框架将测试失败归入 Failure,同时标志为未通过测试。如果在断言方法中指定了字符串形式的失败提示,则该失败提示将作为 Failure 的 标识信息,告诉测试人员该失败的详细信息。
- assertAll:断言可以执行一个或多个 Lambda 表达式,如果表达式可成功执行完成,则表明测试通过,否则算测试失败。
- assertArrayEquals:断言两个数组相等。如果两个数组相等,则表明测试通过,否则算测试失败。Assertions 为该方法提供了多个重载版本,从而支持各种类型的数组。
- assertEquals:断言两个对象(或值)相等。如果两个对象(或值)相等,则表明测试通过,否则算测试失败。Assertions 为该方法提供了多个重载版本,从而支持各种类型的数据。
- assertLinesMatch:断言两个多行字符串逐行相等。如果两个多行字符串逐行相等,则表明测试通过,否则算测试失败。
- assertNotEquals:断言两个对象(或值)不相等。如果两个对象(或值)不相等,则表明测试通过,否则算测试失败。Assertions 为该方法提供了多个重载版本,从而支持各种类型的数据。
- assertSame:断言两个对象(或值)相同。如果两个对象(或值)相同,则表明测试通过,否则算测试失败。Assertions 为该方法提供了多个重载版本,从而支持各种类型的数据。
- assertNotSame:断言两个对象(或值)不相同。如果两个对象(或值)不相同,则表明测试通过, 否则算测试失败。Assertions 为该方法提供了多个重载版本,从而支持各种类型的数据。
- assertThrows:断言执行某个 Lambda 表达式一定会抛出指定的异常。如果抛出该异常,则表明测试 通过,否则算测试失败。
- assertTimeout:断言执行某个 Lambda 表达式不超过指定时间。如果执行该 Lambda 表达式超出了指 定时间,则表明测试失败,否则算测试通过。
- assertNotNull:断言某个变量非空。如果该变量不为 null,则表明测试通过,否则算测试失败。
- assertNull:断言某个变量为空。如果该变量为 null,则表明测试通过,否则算测试失败。
- assertFalse:断言某个变量为 false。如果该变量为 false,则表明测试通过,否则算测试失败。
- assertTrue:断言某个变量为 true。如果该变量为 true,则表明测试通过,否则算测试失败。
2,Mock测试
2.1,基本概念
Mock 测试就是在测试过程中,对于某些不容易构造或者不容易获取的比较复杂的对象,用一个虚拟的对象(Mock 对象)来创建以便测试的测试方法。
Mock是为了解决不同的单元之间由于耦合而难于开发、测试的问题。所以,Mock既能出现在单元测试中,也会出现在集成测试、系统测试过程中。Mock 最大的功能是帮你 把单元测试的耦合分解开,如果你的代码对另一个类或者接口有依赖,它能够帮你模拟这些依赖,并帮你验证所调用的依赖的行为。
//使用jsonPaht验证返回的json中code、message字段的返回值 .andExpect(MockMvcResultMatchers.jsonPath("$.code").value("00000")) .andExpect(MockMvcResultMatchers.jsonPath("$.message").value("成功")) //body属性不为空 .andExpect(MockMvcResultMatchers.jsonPath("$.body").isNotEmpty()) // 期望的返回结果集合有2个元素 , $: 返回结果 .andExpect(MockMvcResultMatchers.jsonPath("$.length()").value(2));RequestBuilder/MockMvcRequestBuilders:
//根据uri模板和uri变量值得到一个GET请求方式的MockHttpServletRequestBuilder; MockHttpServletRequestBuilder get(String urlTemplate, Object... urlVariables) //同get类似,但是是POST方法; MockHttpServletRequestBuilder post(String urlTemplate, Object... urlVariables) //同get类似,但是是PUT方法; MockHttpServletRequestBuilder put(String urlTemplate, Object... urlVariables) //同get类似,但是是DELETE方法; MockHttpServletRequestBuilder delete(String urlTemplate, Object... urlVariables) //同get类似,但是是OPTIONS方法; MockHttpServletRequestBuilder options(String urlTemplate, Object... urlVariables) //提供自己的Http请求方法及uri模板和uri变量,如上API都是委托给这个API; MockHttpServletRequestBuilder request(HttpMethod httpMethod, String urlTemplate, Object... urlVariables) //提供文件上传方式的请求,得到MockMultipartHttpServletRequestBuilder; MockMultipartHttpServletRequestBuilder fileUpload(String urlTemplate, Object... urlVariables) //创建一个从启动异步处理的请求的MvcResult进行异步分派的RequestBuilder; RequestBuilder asyncDispatch(final MvcResult mvcResult)MockHttpServletRequestBuilder:
//:添加头信息; MockHttpServletRequestBuilder header(String name, Object... values)/MockHttpServletRequestBuilder headers(HttpHeaders httpHeaders) //:指定请求的contentType头信息; MockHttpServletRequestBuilder contentType(MediaType mediaType) //:指定请求的Accept头信息; MockHttpServletRequestBuilder accept(MediaType... mediaTypes)/MockHttpServletRequestBuilder accept(String... mediaTypes) //:指定请求Body体内容; MockHttpServletRequestBuilder content(byte[] content)/MockHttpServletRequestBuilder content(String content) //:请求传入参数 MockHttpServletRequestBuilder param(String name,String... values) //:指定请求的Cookie; MockHttpServletRequestBuilder cookie(Cookie... cookies) //:指定请求的Locale; MockHttpServletRequestBuilder locale(Locale locale) //:指定请求字符编码; MockHttpServletRequestBuilder characterEncoding(String encoding) //:设置请求属性数据; MockHttpServletRequestBuilder requestAttr(String name, Object value) //:设置请求session属性数据; MockHttpServletRequestBuilder sessionAttr(String name, Object value)/MockHttpServletRequestBuilder sessionAttrs(Map<string, object=""> sessionAttributes) //指定请求的flash信息,比如重定向后的属性信息; MockHttpServletRequestBuilder flashAttr(String name, Object value)/MockHttpServletRequestBuilder flashAttrs(Map<string, object=""> flashAttributes) //:指定请求的Session; MockHttpServletRequestBuilder session(MockHttpSession session) // :指定请求的Principal; MockHttpServletRequestBuilder principal(Principal principal) //:指定请求的上下文路径,必须以“/”开头,且不能以“/”结尾; MockHttpServletRequestBuilder contextPath(String contextPath) //:请求的路径信息,必须以“/”开头; MockHttpServletRequestBuilder pathInfo(String pathInfo) //:请求是否使用安全通道; MockHttpServletRequestBuilder secure(boolean secure) //:请求的后处理器,用于自定义一些请求处理的扩展点; MockHttpServletRequestBuilder with(RequestPostProcessor postProcessor)ResultActions:
//:添加验证断言来判断执行请求后的结果是否是预期的; ResultActions andExpect(ResultMatcher matcher) //:添加结果处理器,用于对验证成功后执行的动作,如输出下请求/结果信息用于调试; ResultActions andDo(ResultHandler handler) //:返回验证成功后的MvcResult;用于自定义验证/下一步的异步处理; MvcResult andReturn()ResultMatcher/MockMvcResultMatchers:
//:请求的Handler验证器,比如验证处理器类型/方法名;此处的Handler其实就是处理请求的控制器; HandlerResultMatchers handler() //:得到RequestResultMatchers验证器; RequestResultMatchers request() //:得到模型验证器; ModelResultMatchers model() //:得到视图验证器; ViewResultMatchers view() //:得到Flash属性验证; FlashAttributeResultMatchers flash() //:得到响应状态验证器; StatusResultMatchers status() //:得到响应Header验证器; HeaderResultMatchers header() //:得到响应Cookie验证器; CookieResultMatchers cookie() //:得到响应内容验证器; ContentResultMatchers content() //:得到Json表达式验证器; JsonPathResultMatchers jsonPath(String expression, Object ... args)/ResultMatcher jsonPath(String expression, Matcher matcher) //:得到Xpath表达式验证器; XpathResultMatchers xpath(String expression, Object... args)/XpathResultMatchers xpath(String expression, Map<string, string=""> namespaces, Object... args) //:验证处理完请求后转发的url(绝对匹配); ResultMatcher forwardedUrl(final String expectedUrl) //:验证处理完请求后转发的url(Ant风格模式匹配,@since spring4); ResultMatcher forwardedUrlPattern(final String urlPattern) //:验证处理完请求后重定向的url(绝对匹配); ResultMatcher redirectedUrl(final String expectedUrl) //:验证处理完请求后重定向的url(Ant风格模式匹配,@since spring4); ResultMatcher redirectedUrlPattern(final String expectedUrl)
2.2,基本用法
Mockito基本使用方法:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.nudt</groupId> <artifactId>Test</artifactId> <version>1.0-SNAPSHOT</version> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> <version>2.8.9</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-module-junit4</artifactId> <version>1.7.4</version> </dependency> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-api-mockito2</artifactId> <version>1.7.4</version> </dependency> </dependencies> </project>public class MockTest { @Test public void test() { LinkedList mockedList = mock(LinkedList.class); when(mockedList.get(anyInt())).thenReturn("first"); Assert.assertEquals(mockedList.get(0), "first"); } }@RunWith(MockitoJUnitRunner.class) public class MockTest { @Mock private Calculator calculator; @Test public void tester() { //初始化动作 MockitoAnnotations.initMocks(this); when(calculator.add(anyInt(), anyInt())).thenReturn(0); int result = calculator.add(1, 2); Assert.assertEquals(result, 0); } }
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/119357.html

