@WebMvcTest
class HelloControllerTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private HelloController helloController;
@Test
public void greetingShouldReturnMessageFromService() throws Exception {
Mockito.when(service.greet()).thenReturn("Hello, Mock");
this.mockMvc.perform(get("/greeting")).andDo(print()).andExpect(status().isOk())
.andExpect(content().string(containsString("Hello, Mock")));
上面的代码我们用到了 Mockito, 可能你听过周杰伦一首新歌叫 Mojito ,对,Mockito 的命名就是对 Mojito(一种传统的古巴高球鸡尾酒)的戏称
简单来说 Mockito
是一个 java 做单元测试的 Mock 框架:site.mockito.org/
解释下我们上面这行代码 Mockito.when(service.greet()).thenReturn("Hello, Mock");
意为: 当调用 service 的 greet 方法的时候,返回值为 “Hello Mock”,其实没真调那个方法,就是 Mock 了一下,直接给了个返回值。用英文说就是 :When the x method is called then return y
当然 Mockito 在假造上是很有实力的,它有丰富的 API 供你组合使用,有兴趣可以看一看文档和源码注释。
讲到这儿,一定有同学会问,只测 Controller ,那我就用 Postman 就行 了,甚至 curl 都行,为啥要写用例,我不写用例。
哈哈,我相信很多后端同学都没认认真真把用例写完,尤其是 controller 这层的,不装逼,我也是。那我们有必要讨论一下 到底是用 Postman 还是用 MockMVC ?
首先说说 MockMVC 的好处:
- 可编程,这就给了你无限的自由空间,想怎么折腾随便你,你是上帝
- 除了写的时候花点时间外,调试的时候速度快,而且可配置,你要想只测 controller,就只启动 controller 的上下文就行了
- 顺便把测试用例写了,测试同学省心了,给自动化测试提供了基础
- 间接提高代码质量
其他的我不说,我就说最后一点。我注意到一个现象,很多开发同学拿测试同学当工具人,自己写的代码自己不怎么测试,直接交给测试让他们提 BUG,然后改,BUG 多也不觉得害臊。开发是爽了,由于代码质量差,整个项目的进度都被拖慢了。你可能会说这是软件质量管理的问题,是规则制定的有问题,如果出 BUG 扣钱就没这事儿了。
我要说的是,在软件开发这个领域,很多事情不是刻板的死规则,即便是制定了这样的规则,也不一定有效。更多的时候是整个团队的文化和风气,领导者有责任将整个研发团队的文化和风气带向正轨。什么是正轨 ? 其实我们都知道! 我们都知道应该写高质量的代码,bug 少的代码,设计合理的代码,不断重构、不断维护的代码,我们都知道要做好自己的事就会提高整个团队的效率,我们都知道应该写注释、写文档,我们都知道.....
我们都知道,但我们也知道项目时间紧,而且专门有人一遍遍强调 deadLine ,有人关心你的开发进度,关心功能实现了没有,关心老板有没有意见,没有人关心你累不累,关心你几点下的班,关心规划合不合理,关心代码质量高不高,关心与软件真正有关系的一切。所以做一个真正的 软件研发团队的 Leader 不容易,遇到好 Leader 是你的福气。
扯多了,我们回头来看 Postman ,Postman 的好处好像也不用我多说了,确实,如果只是简单的做 Controller 连通测试,用 Postman 一点儿问题没有,也比写程序快,但如果你的需求时有正好是 MockMVC 的优点可以覆盖的地方,那么就动动手,写写程序吧。
想成一份漂亮的测试报告 ? 后端同学说了,整那花里胡哨的有啥用呢,简单一点儿不好吗?
好,简单点儿当然可以,但 UI 带给我们的价值不就是一图胜千言嘛,让无论是前端、后端、测试同学都能一目了然,减轻大脑处理信息的成本。
来,我们先上成果
怎么样,还挺好看的吧,我们用的是 Allure 来生成了一个 web 页面,这个页面还有一些简单的交互,整体简洁好看、易用。
下面我们说一下 Allure 怎么和 JUnit 集成的
我们仍然使用 SpringBoot 以及 JUnit 5 ,先修改一下 pom.xml 文件,添加依赖
<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>
<!--测试报告 allure -->
<dependency>
<groupId>io.qameta.allure</groupId>
<artifactId>allure-junit5</artifactId>
<version>2.18.1</version>
<scope>test</scope>
</dependency>
然而我们添加在 build 中两个 plugin
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.21.0</version>
<configuration>
<testFailureIgnore>false</testFailureIgnore>
<argLine>
-javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar"
</argLine>
<systemProperties>
<property>
<name>junit.jupiter.extensions.autodetection.enabled</name>
<value>true</value>
</property>
</systemProperties>
</configuration>
<dependencies>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-surefire-provider</artifactId>
<version>1.2.0</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>io.qameta.allure</groupId>
<artifactId>allure-maven</artifactId>
<version>2.11.2</version>
<configuration>
<reportVersion>2.4.1</reportVersion>
</configuration>
</plugin>
我们用 brew 在本地安装一下 Allure (我是 mac 就用这个装了,如果你是其他环境参考后面说的文档)
brew install allure
接着我们调整项目中的测试用例,然后执行:
mvn clean test
接着找到你项目中 surefire-reports
的目录位置
然后执行类似如下命令:
# 注意路径改成你自己项目的,这里只是示例
allure serve /home/path/to/project/target/surefire-reports/
显示如下信息会自动跳转到浏览器,打开测试报告页面。
是不是很简单?
有关 JUnit5 就聊到这儿,日常一般的开发是够用了。更多的细节和功能,绍假设 、 断言等,请看官方文档 ,当然备不注它也有错的时候。
TestNG
TestNG is a testing framework inspired from JUnit and NUnit but introducing some new functionalities that make it more powerful and easier to use, such as:
- Annotations.
- Run your tests in arbitrarily big thread pools with various policies available (all methods in their own thread, one thread per test class, etc...).
- Test that your code is multithread safe.
- Flexible test configuration.
- Support for data-driven testing (with @DataProvider).
- Support for parameters.
- Powerful execution model (no more TestSuite).
- Supported by a variety of tools and plug-ins (Eclipse, IDEA, Maven, etc...).
- Embeds BeanShell for further flexibility.
- Default JDK functions for runtime and logging (no dependencies).
- Dependent methods for application server testing.
上面是 TestNG 的官方介绍,看起来比 JUnit 功能还强大。有了前面 Junit 作为引子, 你再看 TestNG,就好理解的多,因为概念上都差不多,只是功能和细节的不同而已。在这里我们不会展开讲 TestNG 了,但是会讨论一下选型的问题。
如果在 JUnit 5 没出来之前,比如 JUnit4 和 3 的时代,我会毫不犹豫地选择 TestNG,为什么?功能强大,好用啊。但是现在 JUnit5 来了,而且推广的势头也很猛,重要的是从功能上也不输 TestNG,那么怎么选呢?
个人觉得:
- 如果是后端开发,一般还是选 JUnit 5 写单元测试方便简单些,SpringBoot 也内置了 JUnit 开箱即用,从生态和社区上讲即使有坑也好解决些
- 如果是搞自动化测试的同学,更多的可能还是用 TestNG 方便些,之前很多遗留项目都是用的 TestNG,另外它和自动化测试工具 selenium 的搭配也早已深入人心。从设计理念到 API,都更符合测试同学的思维。
我觉得不是 java 单元测试的必要性,而是工程的单元测试必要性,和语言无关。当你的项目小的时候,简单的时候,当然单元测试没什么用。但是如果是写底层框架或者一些很大的项目时,单元测试对于提高生产力很有用。单元测试的好处是给人的,不是给机器的。而且从程序设计的角度上看:单元测试可以让你更好的拆分程序为最小单元,帮助你更好的解耦。用到单元测试则必不可少的会用一些自动单元测试框架,对完成工程的自动化测试...
单元测试就是针对最小的功能单元编写测试代码,Java程序最小的功能单元是方法,因此,单元测试就是针对Java方法的测试,进而检查方法的正确性。今天要介绍的是一款JAVA单元测试框架JUnitJUnit是使用Java语言实现的单元测试框架,它是开源的,Java开发者都应当学习并使用JUnit编写单元测试。此外,几乎所有的IDE工具都集成了JUnit,这样我们就可以直接在IDE中编写并运行JUnit测试,JUnit目前最新版本是5。那我们为什么要使用JUnit呢?它有什么优点?......
PowerMock作为一个优秀的单元测试框架,是一个扩展了其它如EasyMock等mock框架的、功能更加强大的框架集合。本文从准备环境入手,通过常用的spy、mock、when、verify语句和参数匹配器、私有属性、私有方法、主要注解的介绍,基本对有一个大概的了解,并阐述了单元测试的个人观点。
Java 单元测试是指对软件中的最小可测试单元进行测试,以保证代码的质量和正确性,并且可以加速开发过程。本文将全面详细地介绍 Java 单元测试相关知识点,包括单元测试的定义、优点和流程、JUnit 测试框架、Mockito 框架、持续集成、代码覆盖率和测试驱动开发等,希望读者能够了解这些知识点,并更好地应用它们来提升自己的开发水平。单元测试的定义单元测试是指对软件中的最小可测试单元进行测试,包括函数、方法和类等。它可以独立地测试每个组件,以保证代码的质量和正确性,并且可以加速开发过程。
链接:https://www.zhihu.com/question/449470796/answer/1781246366
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
编写Java单元测试用例,其实就是把“复杂的问题要简单化”——即把一段复杂的代码拆解成一系列简单的单元测试用例;写好Java单元测试用例,其实就是把“简单的问题要深入化”——即学习一套方法、总结一套模式并应用到实践中。这里,作者根据日常的工作经验,总结了一些Java单元测试技巧,以供.