2.2.2、@DisplayName :为测试类或者测试方法设置展示名称
2.2.3、@BeforeEach、@AfterEach、@BeforeAll、@AfterAll
2.2.4、@Disabled :表示测试类或测试方法不执行
2.2.5、@Timeout :表示测试方法运行如果超过了指定时间将会返回错误
2.2.6、@RepeatedTest :表示方法可重复执行
JUnit5 由三个不同子项目的几个不同模块组成。
JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage
1)JUnit Platform: 是在JVM上启动测试框架的基础,不仅支持Junit自制的测试引擎,其他测试引擎也都可以接入。
2)JUnit Jupiter: 提供了JUnit5的新的编程模型,是JUnit5新特性的核心。内部包含了一个测试引擎,用于在Junit Platform上运行。
3)JUnit Vintage: 由于JUint已经发展多年,为了照顾老的项目,其提供了兼容JUnit4.x,Junit3.x的测试引擎。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>

@SpringBootTest注解:添加在需要依赖springboot框架的测试类上,
不然不能使用Springboot的相关开发功能
@Test注解:添加在测试方法上
@SpringBootTest
class Boot05WebAdminApplicationTests {
@Test
void contextLoads() {
}
}
@Slf4j
@SpringBootTest
class SpringBootThymeleafApplicationTests {
@Autowired
JdbcTemplate jdbcTemplate;
@Autowired
DataSource dataSource;
@Autowired
UserMapper userMapper;
@Autowired
StringRedisTemplate redisTemplate;
@Test
void contextLoads() {
Long along = jdbcTemplate.queryForObject("select count(*) from account", long.class);
log.info("记录总数{}", along);
log.info("数据源类型{}", dataSource.getClass());
}
@Test
void testUserMapper() {
User user = userMapper.selectById(1);
log.info("用户信息{}", user);
}
@Test
void testRedis() {
ValueOperations<String, String> operations = redisTemplate.opsForValue();
operations.set("hello", "world");
String hello = operations.get("hello");
System.out.println(hello);
}
}
@SpringBootTest
class Boot05WebAdminApplicationTests {
@Test
void contextLoads() {
}
}
测试代码:
@DisplayName("junit5功能测试")
public class Junit5Test {
@DisplayName("测试displayname注解")
@Test
void testDisplayName() {
System.out.println(1);
}
}
输出结果:

注解功能:
| 注解 | 功能 |
| @BeforeEach | 表示在每个单元测试之前执行 |
| @AfterEach | 表示在每个单元测试之后执行 |
| @BeforeAll | 表示在所有单元测试之前执行 |
| @AfterAll | 表示在所有单元测试之后执行 |
测试代码:
@SpringBootTest
@DisplayName("junit5功能测试")
public class Junit5Test {
@Autowired
JdbcTemplate jdbcTemplate;
/**
* 测试前置条件
*/
@DisplayName("测试前置条件")
@Test
void testAssumptions() {
Assumptions.assumeTrue(false, "结果不足true");
System.out.println("11111");
}
@DisplayName("测试displayname注解")
@Test
void testDisplayName() {
System.out.println(1);
}
@Disabled
@DisplayName("测试2")
@Test
void test2() {
System.out.println(2);
System.out.println(jdbcTemplate.getClass());
}
@BeforeEach
void testBeforeEach() {
System.out.println("测试就要开始。。。");
}
@AfterEach
void testAfterEach() {
System.out.println("测试就要结束。。。");
}
@BeforeAll
static void testBeforeAll() {
System.out.println("所有测试就要开始。。。");
}
@AfterAll
static void testAfterAll() {
System.out.println("所有测试已经结束。。。");
}
}
输出结果:

测试代码:
@Disabled
@DisplayName("测试2")
@Test
void test2() {
System.out.println(2);
System.out.println(jdbcTemplate.getClass());
}
测试代码:设置执行时间为500ms,超时报错
@Test
@Timeout(value = 500, unit = TimeUnit.MILLISECONDS)
void testTimeOut() throws InterruptedException {
Thread.sleep(520);
}
返回结果:

测试代码:
@RepeatedTest(5) //重复测试5次
@DisplayName("测试3")
@Test
void test3() {
System.out.println(3);
System.out.println(jdbcTemplate.getClass());
}
执行结果:

@ParameterizedTest :表示方法是参数化测试
@Tag :表示单元测试类别
@ExtendWith :为测试类或测试方法提供扩展类引用
1)简单断言功能:
| 方法 | 说明 |
| assertEquals | 判断两个对象或两个原始类型是否相等 |
| assertNotEquals | 判断两个对象或两个原始类型是否不相等 |
| assertSame | 判断两个对象引用是否指向同一个对象 |
| assertNotSame | 判断两个对象引用是否指向不同的对象 |
| assertTrue | 判断给定的布尔值是否为 true |
| assertFalse | 判断给定的布尔值是否为 false |
| assertNull | 判断给定的对象引用是否为 null |
| assertNotNull | 判断给定的对象引用是否不为 null |
2)测试代码:
@SpringBootTest
@DisplayName("junit5功能测试")
public class Junit5Test {
@DisplayName("测试简单断言")
@Test
void testSimpleAssertions() {
int call = call(1,2);
assertEquals(2, call, "业务逻辑计算失败");
Object obj1 = new Object();
Object obj2 = new Object();
assertSame(obj1, obj2, "两个对象不一样");
}
int call (int x, int y) {
return x + y;
}
}
}
3)测试结果:

通过 assertArrayEquals 方法来判断两个对象或原始类型的数组是否相等
测试代码:
@Test
@DisplayName("array assertion")
public void array() {
assertArrayEquals(new int[]{1, 2}, new int[] {1, 2});
}
assertAll 方法接受多个 org.junit.jupiter.api.Executable 函数式接口的实例作为要验证的断言
可以通过 lambda 表达式很容易的提供这些断言
前边断言失败,后续代码不会执行
组合断言,当组合中的所有断言都通过才是true,否则是false
测试代码:
@Test
@DisplayName("assert all")
public void all() {
assertAll("Math",
() -> assertEquals(2, 1 + 1),
() -> assertTrue(1 > 0)
);
}
JUnit5提供了Assertions.assertThrows() ,配合函数式编程就可以进行使用。
@Test
@DisplayName("异常断言")
public void exceptionTest() {
ArithmeticException exception = Assertions.assertThrows(
//扔出断言异常
ArithmeticException.class, () -> System.out.println(1 % 0));
}
Junit5提供了Assertions.assertTimeout() 为测试方法设置了超时时间
@Test
@DisplayName("超时测试")
public void timeoutTest() {
//如果测试方法时间超过1s将会异常
Assertions.assertTimeout(Duration.ofMillis(1000), () -> Thread.sleep(500));
}
@Test
@DisplayName("fail")
public void shouldFail() {
fail("This should fail");
}
测试代码:
@SpringBootTest
@DisplayName("junit5功能测试")
public class Junit5Test {
@Autowired
JdbcTemplate jdbcTemplate;
/**
* 测试前置条件
*/
@DisplayName("测试前置条件")
@Test
void testAssumptions() {
Assumptions.assumeTrue(false, "结果不足true");
System.out.println("11111");
}
}
返回结果:
1.当不满足前置条件时,后续输出代码未执行
2.当不满足前置条件时,程序未报错退出,而是终止执行

注意:
1.外层测试方法的执行,不会驱动内层方法:
当内层方法中有 before 或 after 等注解时,调用外层测试方法,并不会驱动其提前或最后执行
2.内层方法的执行,可以驱动外层方法:
当外层方法定义了某一数据结果时,内层测试方法可以直接调用该结构
测试代码:
@DisplayName("嵌套测试")
public class TestingAstackDemo {
Stack<Object> stack;
@ParameterizedTest
@DisplayName("参数化测试")
@ValueSource(ints = {1, 2, 3, 4, 5})
void testParamterized(int i) {
System.out.println(i);
}
@ParameterizedTest
@DisplayName("参数化方法测试")
@MethodSource("stringProvider")
void testParamterized2(String s) {
System.out.println(s);
}
static Stream<String> stringProvider() {
return Stream.of("apple", "banana");
}
@Test
@DisplayName("is instantiated with new Stack()")
void isInstantiatedWithNew() {
new Stack<>();
//在嵌套测试情况下,外层的test不能驱动内层
//的beforeall等方法,在提前/之后运行
//内层的test可以驱动外层
// assertNotNull(stack);
}
@Nested
@DisplayName("when new")
class WhenNew {
@BeforeEach
void createNewStack() {
stack = new Stack<>();
}
@Test
@DisplayName("is empty")
void isEmpty() {
assertTrue(stack.isEmpty());
}
@Test
@DisplayName("throws EmptyStackException when popped")
void throwsExceptionWhenPopped() {
assertThrows(EmptyStackException.class, stack::pop);
}
@Test
@DisplayName("throws EmptyStackException when peeked")
void throwsExceptionWhenPeeked() {
assertThrows(EmptyStackException.class, stack::peek);
}
@Nested
@DisplayName("after pushing an element")
class AfterPushing {
String anElement = "an element";
@BeforeEach
void pushAnElement() {
stack.push(anElement);
}
@Test
@DisplayName("it is no longer empty")
void isNotEmpty() {
assertFalse(stack.isEmpty());
}
@Test
@DisplayName("returns the element when popped and is empty")
void returnElementWhenPopped() {
assertEquals(anElement, stack.pop());
assertTrue(stack.isEmpty());
}
@Test
@DisplayName("returns the element when peeked but remains not empty")
void returnElementWhenPeeked() {
assertEquals(anElement, stack.peek());
assertFalse(stack.isEmpty());
}
}
}
}
1)参数化测试,可以指定测试方法的输入参数
2)参数化测试的注解类型:
| 注解 | 功能 |
| @ValueSource | 为参数化测试指定入参来源,支持八大基础类以及String类型,Class类型 |
| @NullSource | 表示为参数化测试提供一个null的入参 |
| @EnumSource | 表示为参数化测试提供一个枚举入参 |
| @CsvFileSource | 表示读取指定CSV文件内容作为参数化测试入参 |
| @MethodSource | 表示读取指定方法的返回值作为参数化测试入参(方法的返回值为流) |
测试代码:
1)入参为基础类型
@ParameterizedTest
@DisplayName("参数化测试")
@ValueSource(ints = {1, 2, 3, 4, 5})
void testParamterized(int i) {
System.out.println(i);
}
2)入参为方法返回值类型
@ParameterizedTest
@DisplayName("参数化方法测试")
@MethodSource("stringProvider")
void testParamterized2(String s) {
System.out.println(s);
}
static Stream<String> stringProvider() {
return Stream.of("apple", "banana");
}
很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当
我有一个围绕一些对象的包装类,我想将这些对象用作散列中的键。包装对象和解包装对象应映射到相同的键。一个简单的例子是这样的:classAattr_reader:xdefinitialize(inner)@inner=innerenddefx;@inner.x;enddef==(other)@inner.x==other.xendenda=A.new(o)#oisjustanyobjectthatallowso.xb=A.new(o)h={a=>5}ph[a]#5ph[b]#nil,shouldbe5ph[o]#nil,shouldbe5我试过==、===、eq?并散列所有无济于事。
我有一些Ruby代码,如下所示:Something.createdo|x|x.foo=barend我想编写一个测试,它使用double代替block参数x,这样我就可以调用:x_double.should_receive(:foo).with("whatever").这可能吗? 最佳答案 specify'something'dox=doublex.should_receive(:foo=).with("whatever")Something.should_receive(:create).and_yield(x)#callthere
Sinatra新手;我正在运行一些rspec测试,但在日志中收到了一堆不需要的噪音。如何消除日志中过多的噪音?我仔细检查了环境是否设置为:test,这意味着记录器级别应设置为WARN而不是DEBUG。spec_helper:require"./app"require"sinatra"require"rspec"require"rack/test"require"database_cleaner"require"factory_girl"set:environment,:testFactoryGirl.definition_file_paths=%w{./factories./test/
我遵循MichaelHartl的“RubyonRails教程:学习Web开发”,并创建了检查用户名和电子邮件长度有效性的测试(名称最多50个字符,电子邮件最多255个字符)。test/helpers/application_helper_test.rb的内容是:require'test_helper'classApplicationHelperTest在运行bundleexecraketest时,所有测试都通过了,但我看到以下消息在最后被标记为错误:ERROR["test_full_title_helper",ApplicationHelperTest,1.820016791]test
我已经构建了一些serverspec代码来在多个主机上运行一组测试。问题是当任何测试失败时,测试会在当前主机停止。即使测试失败,我也希望它继续在所有主机上运行。Rakefile:namespace:specdotask:all=>hosts.map{|h|'spec:'+h.split('.')[0]}hosts.eachdo|host|begindesc"Runserverspecto#{host}"RSpec::Core::RakeTask.new(host)do|t|ENV['TARGET_HOST']=hostt.pattern="spec/cfengine3/*_spec.r
我在app/helpers/sessions_helper.rb中有一个帮助程序文件,其中包含一个方法my_preference,它返回当前登录用户的首选项。我想在集成测试中访问该方法。例如,这样我就可以在测试中使用getuser_path(my_preference)。在其他帖子中,我读到这可以通过在测试文件中包含requiresessions_helper来实现,但我仍然收到错误NameError:undefinedlocalvariableormethod'my_preference'.我做错了什么?require'test_helper'require'sessions_hel
只是想确保我理解了事情。据我目前收集到的信息,Cucumber只是一个“包装器”,或者是一种通过将事物分类为功能和步骤来组织测试的好方法,其中实际的单元测试处于步骤阶段。它允许您根据事物的工作方式组织您的测试。对吗? 最佳答案 有点。它是一种组织测试的方式,但不仅如此。它的行为就像最初的Rails集成测试一样,但更易于使用。这里最大的好处是您的session在整个Scenario中保持透明。关于Cucumber的另一件事是您(应该)从使用您的代码的浏览器或客户端的角度进行测试。如果您愿意,您可以使用步骤来构建对象和设置状态,但通常您
我有:When/^(?:|I)follow"([^"]*)"(?:within"([^"]*)")?$/do|link,selector|with_scope(selector)doclick_link(link)endend我打电话的地方:Background:GivenIamanexistingadminuserWhenIfollow"CLIENTS"我的HTML是这样的:CLIENTS我一直收到这个错误:.F-.F--U-----U(::)failedsteps(::)nolinkwithtitle,idortext'CLIENTS'found(Capybara::Element