目录
介绍
JUnit是一种Java语言的单元测试框架,它是最流行的单元测试框架之一。它提供了一些可用于编写和运行测试的API,并且可以生成测试报告。JUnit适用于所有Java语言的项目,例如Java应用程序、Java Servlet、Java EE应用程序以及Android应用程序等。
依赖
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
RunWith
Springboot集成JUnit写单元测试类需要使用RunWith注解,这个注解需要一个值,测试运行器。
测试运行器(Test Runner)是JUnit框架提供的一个核心组件,用于执行测试类中的测试方法并生成测试报告。JUnit提供了多个测试运行器,不同的运行器可以根据不同的需求来选择使用。
- JUnit4:JUnit4是JUnit框架的主流版本,支持使用注解方式进行测试。我们一般会选择使用@RunWith(JUnit4.class)运行器来执行测试用例。
- SpringRunner:SpringRunner是Spring Boot Test框架中提供的测试运行器,用于执行集成测试和端到端测试等。可以使用@RunWith(SpringRunner.class)运行器来启动Spring Boot上下文环境,并进行测试。
- Parameterized:Parameterized是JUnit提供的一个参数化测试运行器,可以让我们在单元测试中重复运行相同的测试方法,并对方法参数进行变量化处理。
- Theories:Theories是JUnit提供的一个更加高级的参数化测试运行器,可以生成随机数据、枚举值、自定义输入等多种方式来测试方法的正确性。
- Suite:Suite运行器可以将多个测试类组合成一组测试用例,方便批量执行和管理测试用例。
Assert类
Assert是JUnit框架提供的一个断言类,用于验证测试结果和预期结果是否相符。我们可以使用Assert类来编写断言代码,从而保证测试的正确性和可靠性。
- assertEquals(expected, actual):验证两个值是否相等,如果不相等则抛出AssertionError异常。
- assertNotEquals(expected, actual):验证两个值是否不相等,如果相等则抛出AssertionError异常。
- assertTrue(condition):验证给定的条件是否为true,如果不是则抛出AssertionError异常。
- assertFalse(condition):验证给定的条件是否为false,如果不是则抛出AssertionError异常。
- assertNull(object):验证给定对象是否为空(null),如果不为空则抛出AssertionError异常。
- assertNotNull(object):验证给定对象是否不为空(null),如果为空则抛出AssertionError异常。
- assertArrayEquals(expected, actual):验证两个数组是否相等,如果不相等则抛出AssertionError异常。
- assertSame(expected, actual):验证两个对象是否相等,如果不相等则抛出AssertionError异常。
- assertNotSame(notExpected, actual):验证两个对象是否不相等,如果相等则抛出AssertionError异常。
断言方法的第一个参数通常是预期值(expected),而第二个参数则是实际值(actual)。
JUnit的注解
- @Test:这是JUnit最重要的注解之一,它被用来标记测试方法。JUnit会执行所有带有@Test注解的方法,以验证代码的正确性。
- @Before:在每个测试方法执行之前该注解所标注的方法会被执行。通常,这个注解可以用于初始化测试数据和资源。
- @After:在每个测试方法执行之后该注解所标注的方法会被执行。通常,这个注解可以用于清理测试数据和资源。
- @BeforeClass:在整个测试类中只执行一次,在执行测试用例之前该注解所标注的方法会被执行,且这个方法必须是静态方法,也就是这个方法会在类加载时执行。通常,这个注解可以用于初始化静态数据和资源。
- @AfterClass:在整个测试类中只执行一次,在执行测试用例之后该注解所标注的方法会被执行,同样,这个方法必须是静态方法。通常,这个注解可以用于清理静态数据和资源。
- @Ignore:该注解表示忽略某个测试方法,不会执行该方法。通常,这个注解可以用于临时禁用某个测试用例。
- @RunWith:该注解定义测试运行器,JUnit默认使用BlockJUnit4ClassRunner作为测试运行器。如果需要使用其他运行器,可以在注解中指定。
- @Parameters:该注解可以用于动态参数化测试方法,使测试方法能够接受不同的输入参数。
- @Rule:该注解定义测试规则(Test Rule),可以在测试方法执行前后实施某些操作,如超时控制、异常检测等。
- @ClassRule:类似于@Rule,但是粒度更大,可以对整个测试类进行规则控制。
使用@Test可能遇见的问题:
不能加载通过@Autowired注解引入的Spring bean
org.junit的Test不能使用spring的bean而org.junit.jupiter.api的Test可以
org.junit.jupiter.api.Test
org.junit.Test
org.junit的Test和org.junit.jupiter.api的Test注解本质上并没有限制能否使用spring的bean,但是它们对于test执行时的上下文环境有所不同。
在JUnit 4中(org.junit.Test),测试类是由JUnit框架进行实例化。当使用JUnit 4的@Test注解时,测试类的实例是由JUnit框架直接创建的,而不是由Spring容器创建的。因此,如果您试图在JUnit 4测试中使用spring bean,就需要手动创建bean并注入到测试类中,或将bean作为参数传递给测试方法。
而在JUnit 5中(org.junit.jupiter.api.Test),测试实例可以由Spring容器创建。JUnit 5引入了@SpringBootTest注解,该注解用于启用Spring的上下文,将测试实例化为Spring bean,并允许使用@Autowired注解来注入其他Spring bean。这样,测试实例就可以使用Spring应用程序上下文中的任何bean和服务,包括JdbcTemplate等。
Parameters
该注解用于动态参数化测试方法,允许为每个测试运行提供不同的输入参数。
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.Arrays;
import java.util.Collection;
import static org.junit.Assert.assertEquals;
@SpringBootTest
@RunWith(Parameterized.class)
public class JunitTest {
@Parameterized.Parameters
public static Collection<Object[]> data() {
return Arrays.asList(new Object[][]{{1, 2}, {3, 4}, {5, 6}});
}
private int input;
private int expected;
public JunitTest(int input, int expected) {
this.input = input;
this.expected = expected;
}
@Test
public void test() {
assertEquals(expected, input + 1);
}
}
在这个例子中,我们有一个JunitTest 类,它有一个带有两个参数的构造函数。为了测试JunitTest 类的行为是否正确,我们使用JUnit的@Parameters注解来动态生成多组输入参数,并分别对每个参数运行测试方法。
每组参数由一个长度为2的Object数组表示,第一个元素代表输入值,第二个元素代表期望输出值。
在JUnit中,@RunWith(Parameterized.class)注解指定了JUnit要使用参数化测试运行器来运行测试方法。@Parameters注解用于指定参数集合,该示例中,我们返回了一个数组列表,其中每个元素都是长度为2的Object数组,表示要测试的输入和期望输出值。
在这个示例中,我们测试了三个参数组,并分别检查它们的输出是否正确。
Rule
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.Timeout;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@SpringBootTest
@RunWith(SpringRunner.class)
public class JunitTest {
@Rule
public Timeout globalTimeout = Timeout.seconds(10);
@Test
public void test() {
try {
Thread.sleep(15000); //org.junit.runners.model.TestTimedOutException: test timed out after 10 seconds
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
Assert.assertEquals(5, 5);
}
}
测试规则
除了上面的超时还有:
ExpectedException 规则
ExpectedException 规则可以验证预期的异常是否被抛出,并检查异常消息和类型是否正确。它通常用于测试方法在给定错误输入时是否正确地抛出异常。
public class MyTest {
@Rule
public ExpectedException exception = ExpectedException.none();
@Test
public void test() {
exception.expect(IOException.class);
exception.expectMessage("File not found");
// some code that throws an IOException with message "File not found"
}
}
test方法抛出的异常和exception期待的异常及异常message相同则测试成功
TemporaryFolder 规则
TemporaryFolder 规则可以创建临时目录和临时文件,以便在测试中保存数据和状态。它通常用于模拟测试环境和确保测试数据不会影响程序的实际运行环境。
public class MyTest {
@Rule
public TemporaryFolder folder = new TemporaryFolder();
@Test
public void test() throws IOException {
File file = folder.newFile("test.txt");
assertTrue(file.exists());
}
}
在这个例子中,我们定义了一个 TemporaryFolder 规则,然后在测试方法中使用 newFile() 方法来创建一个新文件。TemporaryFolder 规则会自动清理临时文件和目录,以确保测试不会影响到实际文件系统。
Stopwatch 规则
Stopwatch 规则可以测量测试方法的运行时间,并检查是否超过了预定的时间阈值。它通常用于确保测试方法在合理的时间内完成,避免测试用例过于耗时或死循环等问题。
public class MyTest {
@Rule
public Stopwatch stopwatch = new Stopwatch() {
@Override
protected void succeeded(long nanos, Description description) {
assertTrue(nanos < TimeUnit.SECONDS.toNanos(1));
}
};
@Test
public void test() throws InterruptedException {
Thread.sleep(900);
}
}
在这个例子中,我们定义了一个 Stopwatch 规则,并覆盖了其 succeeded() 方法来检查测试方法是否在1秒内完成。如果测试方法过于耗时,则测试失败。
TestName 规则
TestName 规则可以获取当前测试方法的名称,并将其保存到一个 String 类型的变量中。它通常用于将测试方法的名称与输出结果关联起来,以便更好地了解测试方法的行为和结果。
public class MyTest {
@Rule
public TestName testName = new TestName();
@Test
public void test() {
System.out.println(testName.getMethodName());
// output: test
}
}
在这个例子中,我们定义了一个 TestName 规则,并在测试方法中使用 getMethodName() 方法来获取当前测试方法的名称。我们使用 System.out.println() 将测试方法的名称输出到控制台。
ExternalResource 规则
ExternalResource 规则可以在测试方法执行前创建资源,并在方法执行完毕后清理资源。它通常用于模拟外部资源,如数据库连接、网络连接等。
public class MyTest {
@Rule
public ExternalResource resource = new ExternalResource() {
private ResourceObject resource;
@Override
protected void before() throws Throwable {
resource = new ResourceObject();
resource.connect();
}
@Override
protected void after() {
resource.disconnect();
}
};
@Test
public void test() {
// some code that uses the resource object
}
}
在这个例子中,我们定义了一个 ExternalResource 规则,并覆盖了其 before() 和 after() 方法来创建和清理资源。在测试方法中,我们可以使用创建好的资源对象执行测试。
ErrorCollector 规则
ErrorCollector 规则可以收集测试过程中发生的所有错误,并在测试结束时一次性输出错误消息。它通常用于测试方法涉及多个步骤或条件,其中任何一个步骤或条件失败都会导致整个测试失败。
public class MyTest {
@Rule
public ErrorCollector collector = new ErrorCollector();
@Test
public void test() {
int result1 = someMethod();
collector.checkThat(result1, equalTo(10));
int result2 = someOtherMethod();
collector.checkThat(result2, equalTo(20));
// some more code that may throw exceptions or fail assertions
}
}
在这个例子中,我们定义了一个 ErrorCollector 规则,并在测试方法中使用 checkThat() 方法来检查每个步骤的结果是否符合预期。如果任何一个步骤失败,则该测试失败,并且所有错误消息都会在测试结束时输出。
ClassRule
该注解与@Rule类似,但是它作用于整个测试类而不是每个测试方法。
例子
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@SpringBootTest
@RunWith(SpringRunner.class)
public class JunitTest {
@BeforeClass
public static void beforeClass() {
System.out.println("beforeClass");
}
@Before
public void before() {
System.out.println("before");
}
@Test
public void test() {
int actual = 5;
Assert.assertEquals(5, actual);
System.out.println("test");
}
@Test
public void test1() {
int actual = 8;
Assert.assertEquals(8, actual);
System.out.println("test1");
}
}