一、环境
使用idea2017.2.3,maven3.5,基于版本junit4.12,大部分内容基于网上整理而来
pom.xml:
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
二、基本测试
要测试的类Calculator,这是一个能够简单实现加减乘除、平方、开方的计算器类
public class Calculator {
private static int result; // 静态变量,用于存储运行结果
public void add(int n) {
result = result + n;
}
public void substract(int n) {
result = result - 1; //Bug: 正确的应该是 result =result-n
}
public void multiply(int n) {
} // 此方法尚未写好
public void divide(int n) {
result = result / n;
}
public void square(int n) {
result = n * n;
}
public void squareRoot(int n) {
for (; ; ) ; //Bug : 死循环
}
public void clear() { // 将结果清零
result = 0;
}
public int getResult() {
return result;
}
}
快速生成测试类和方法
在类名上,按下alt+enter ,选择Create Test
image.png
选择junit4,选择要测试的方法,这里选择加减乘除
image.png
对生成的测试类CalculatorTest,做一些修改如下
public class CalculatorTest {
private static Calculator calculator = new Calculator();
@Before
public void setUp() throws Exception {
calculator.clear();
}
@Test
public void testAdd() {
calculator.add(3);
calculator.add(4);
assertEquals(7, calculator.getResult());
}
@Test
public void testSubstract() {
calculator.add(8);
calculator.substract(3);
assertEquals(5, calculator.getResult());
}
@Ignore("Multiply() Not yet implemented")
@Test
public void testMultiply() {
fail("Not yet implemented");
}
@Test
public void testDivide() {
calculator.add(8);
calculator.divide(2);
assertEquals(4, calculator.getResult());
}
}
注解的说明
@BeforeClass 全局只会执行一次,而且是第一个运行
@Before 在测试方法运行之前运行
@Test 测试方法
@After 在测试方法运行之后允许
@AfterClass 全局只会执行一次,而且是最后一个运行
@Ignore 忽略此方法
方法的说明
这里用到了两个断言
Assert.assertEquals(expected, actual) 传入预期值跟实际值,断言它们相等
Assert.fail(String message) 在不检查任何条件的情况下使断言失败。显示消息
Run整个Test类,显示结果如下:
image.png
三、限时测试
对于循环、数据库查询、网络请求等可能的耗时操作往往需要限定其操作响应时间。
给@Test加上一个参数timeout来设定要限定的时间,单位为毫秒。
@Test(timeout = 1000)
public void squareRoot() {
calculator.squareRoot(4);
assertEquals(2, calculator.getResult());
}
Run这个测试方法,因为calculator.squareRoot里面是死循环,所以得到一个超时结果
image.png
四、异常测试
某些情况下,应该抛出异常的,我们也需要测试到这种情况
给@Test加上一个参数expected 来设定预期发生的异常
@Test(expected = ArithmeticException.class)
public void divideByZero(){
calculator.divide(0);
}
RunTest通过
当然,还可以进行try...catch操作,在catch里面使用断言来处理得到的异常
@Test
public void divideByZero1() {
try {
calculator.divide(0);
Assert.fail("fail");
} catch (Exception e) {
Assert.assertTrue(e instanceof ArithmeticException);
}
}
五、参数化测试
一个方法可能有多个处理分支,要测试到多个不同的分支就需要不同的测试用例,如果按上面的方法来处理,有多少个测试用例就需要写多少个测试方法,junit提供了另外的选择。
测试calculator.Square方法,把它分三类:正数、0、负数,代码如下
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.util.Arrays;
import java.util.Collection;
//(1)步骤一:测试类指定特殊的运行器org.junit.runners.Parameterized
@RunWith(Parameterized.class)
public class SquareTest {
private static Calculator calculator = new Calculator();
// (2)步骤二:为测试类声明变量,分别用于存放期望值和测试所用数据。
private int param;
private int result;
// (3)步骤三:为测试类声明一个带有参数的公共构造函数,并在其中为第二个环节中声明的几个变量赋值。
public SquareTest(int param, int result) {
this.param = param;
this.result = result;
}
// (4)步骤四:为测试类声明一个使用注解 org.junit.runners.Parameterized.Parameters 修饰的,返回值为java.util.Collection 的公共静态方法,并在此方法中初始化所有需要测试的参数对
@Parameterized.Parameters
public static Collection data() {
return Arrays.asList(new Object[][]{
{2, 4},
{0, 0},
{-3, 9},
});
}
// (5)步骤五:编写测试方法,使用定义的变量作为参数进行测试
@Test
public void square() {
calculator.square(param);
Assert.assertEquals(result, calculator.getResult());
}
}
Run结果
image.png
六、spring测试
更多的时候,都是在使用spring框架进行开发,所以测试环境也需要基于spring
引入spring
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.11.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.11.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.3.11.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.3.11.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.3.11.RELEASE</version>
<scope>test</scope>
</dependency>
测试代码
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:applicationContext.xml"})
public class SpringTest {
@Autowired
private Calculator calculator;
@Test
public void testAdd() {
calculator.clear();
calculator.add(5);
Assert.assertEquals(5, calculator.getResult());
}
}
如果需要在spring框架下使用参数化测试,需要借助TestContextManager类来处理,SpringJUnit4ClassRunner内部其实也是使用TestContextManager来进行的处理
@RunWith(Parameterized.class)
@ContextConfiguration(locations = {"classpath:applicationContext.xml"})
public class SpringSquareTest {
@Autowired
private Calculator calculator;
private int param;
private int result;
private TestContextManager testContextManager;
@Before
public void setUp() {
//自动注解与@RunWith(SpringJUnit4ClassRunner.class) 效果一样
testContextManager = new TestContextManager(getClass());
try {
testContextManager.prepareTestInstance(this);
} catch (Exception e) {
e.printStackTrace();
}
}
@Parameterized.Parameters
public static Collection data() {
return Arrays.asList(new Object[][]{
{2, 4},
{0, 0},
{-3, 9},
});
}
public SpringSquareTest(int param, int result) {
this.param = param;
this.result = result;
}
@Test
public void square() {
calculator.square(param);
assertEquals(result, calculator.getResult());
}
}
七、自定义断言
通过Assert.assertThat(T actual, Matcher<? super T> matcher)来自定义断言
@Test
public void testAssertThat() {
Assert.assertThat("12321", new BaseMatcher<String>() {
@Override
public boolean matches(Object o) {
return "12321".equals(o);
}
@Override
public void describeTo(Description description) {
description.appendText("不相等");
}
});
}
junit已经内置了一些Matcher,可以直接使用,如
Assert.assertThat("Hello,World", startsWith("Hello"));
Assert.assertThat( "Hello,World", both(startsWith("Hello")).and(endsWith("World")));
参考:
网友评论