单元测试是测试代码的最小单元,通常针对单个类或方法。单元测试旨在验证代码是否按预期运行,帮助发现潜在的逻辑错误和bug。一个好的单元测试应该具备以下特点:
JUnit是Java语言中的一个开源测试框架,能够帮助开发者编写可维护、可执行的测试代码。JUnit使得开发者可以方便地组织和执行测试,并生成详细的测试报告。
要使用JUnit,首先需要将其依赖添加到项目中。对于Maven项目,可以在pom.xml中添加以下依赖:
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
被测试类 Calculator.java:
public class Calculator {
public int add(int a, int b) {
return a + b;
}
public int subtract(int a, int b) {
return a - b;
}
}
测试类 CalculatorTest.java:
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class CalculatorTest {
@Test
public void testAdd() {
Calculator calculator = new Calculator();
int result = calculator.add(2, 3);
assertEquals(5, result); // 断言结果应该为5
}
@Test
public void testSubtract() {
Calculator calculator = new Calculator();
int result = calculator.subtract(5, 3);
assertEquals(2, result); // 断言结果应该为2
}
}
在这个例子中,我们使用了两个测试方法testAdd()和testSubtract(),它们分别测试了add()和subtract()方法的正确性。使用@Test注解标记测试方法,assertEquals()方法用来检查实际结果是否与期望结果一致。
例如:
import org.junit.*;
public class JUnitExample {
// 在所有测试方法之前执行,仅执行一次
@BeforeClass
public static void setUpBeforeClass() throws Exception {
System.out.println("执行 @BeforeClass:全局初始化...");
}
// 在所有测试方法之后执行,仅执行一次
@AfterClass
public static void tearDownAfterClass() throws Exception {
System.out.println("执行 @AfterClass:全局清理...");
}
// 在每个测试方法之前执行
@Before
public void setUp() throws Exception {
System.out.println("执行 @Before:测试方法前的初始化...");
}
// 在每个测试方法之后执行
@After
public void tearDown() throws Exception {
System.out.println("执行 @After:测试方法后的清理...");
}
// 标记为测试方法
@Test
public void testMethod1() {
System.out.println("执行 @Test:测试方法1");
Assert.assertEquals(1, 1);
}
// 标记为测试方法
@Test
public void testMethod2() {
System.out.println("执行 @Test:测试方法2");
Assert.assertTrue(true);
}
// 忽略此测试方法
@Ignore("此测试方法被忽略")
@Test
public void ignoredTestMethod() {
System.out.println("此测试方法应该不会被执行");
}
}
输出:
执行 @BeforeClass:全局初始化...
执行 @Before:测试方法前的初始化...
执行 @Test:测试方法1
执行 @After:测试方法后的清理...
执行 @Before:测试方法前的初始化...
执行 @Test:测试方法2
执行 @After:测试方法后的清理...
执行 @AfterClass:全局清理...
assertEquals(5, 3 + 2); // 通过
assertEquals("hello", "hello"); // 通过
assertNotEquals(5, 3 + 3); // 通过
assertTrue(5 > 3); // 通过
assertFalse(5 < 3); // 通过
assertNull(null); // 通过
assertNotNull(new Object()); // 通过
Object obj = new Object();
assertSame(obj, obj); // 通过
assertNotSame(new Object(), new Object()); // 通过
int[] expected = {1, 2, 3};
int[] actual = {1, 2, 3};
assertArrayEquals(expected, actual); // 通过
if (someCondition) {
fail("不应执行到此处");
}
assertThrows(IllegalArgumentException.class, () -> {
throw new IllegalArgumentException("异常测试");
});
assertTimeout(Duration.ofSeconds(1), () -> {
// 一些操作
});
有时候我们希望对一个方法使用多组不同的输入进行测试,而不需要为每组输入编写单独的测试方法。JUnit支持参数化测试,允许我们以参数化的方式运行测试。
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.util.Arrays;
import java.util.Collection;
import static org.junit.Assert.assertEquals;
@RunWith(Parameterized.class)
public class ParameterizedTest {
private int input1;
private int input2;
private int expected;
public ParameterizedTest(int input1, int input2, int expected) {
this.input1 = input1;
this.input2 = input2;
this.expected = expected;
}
@Parameterized.Parameters
public static Collection<Object[]> data() {
return Arrays.asList(new Object[][] {
{1, 1, 2},
{2, 3, 5},
{3, 5, 8}
});
}
@Test
public void testAdd() {
Calculator calculator = new Calculator();
assertEquals(expected, calculator.add(input1, input2));
}
}
在这个例子中,ParameterizedTest类使用了参数化测试运行器,每个测试用例会使用不同的输入值和期望结果来测试add()方法。
有兴趣的小伙伴可以关注我的公众号【知识星球站】一起讨论学习!!