首页 > 编程知识 正文

单元测试junit如何实现测试(junit单元测试原理)

时间:2023-05-04 22:17:57 阅读:66362 作者:3900

全部展开

首先,必须下载相应的JUnit相关JAR包。 下载过程可以直接从JUnit官方62616964757 a 686964616 Fe 59 B9 ee7ad 94313337613862站点进行,也可以直接从Maven资源仓库进行。

使用简单的@Test注释来创建和执行测试方法

准备好了,接下来写一下简单的测试代码吧。 首先,我们制作了一个Calculator类,用五种方法分别完成了求加减乘除和平方的运算。 代码如下。

package net.oschina.bairrfhoinn.main;

公共类计算器{

公共语音添加(Intn ) {

result =n;

}

公共语音订阅(intn ) {

result -=n;

}

公共语音多点(intn ) {

result *=n;

}

公共语音视频(Intn ) {

result /=n;

}

公共语音方案(intn ) {

result=n * n;

}

公共插入获取器

返回结果;

}

公共语音清除器

结果=0;

}

私有静态输入结果;

}

因为在测试类中使用了JUnit4框架,所以当然必须包含相应的Package。 最主要的包是org.junit.*。 包括它在内,几乎所有的功能都有。 另外,“import static org.junit.Assert.*; ”这句话也很重要。 我们在测试时使用的壹系列assertEquals ()方法来自这个包。 请注意壹下。 这是壹个静态包含(static ),是JDK5中新添加的壹个功能。 也就是说,AssertEquals是assert类的壹系列静态方法,壹的用法是Assert. assertEquals (),但使用静态包含可以省略前面的类名,使其更易于使用。

另外,请注意,我们的测试类是一个独立的类,没有父类。 测试类的名称也可以任意命名,没有限制。 因此,不能通过类的声明来确定它是否是测试类。 与普通类的区别在于其内部方法的声明。 接下来说明。 在测试类中,并不是每个方法都用于测试,因此必须使用“注释”来明确说明测试方法。 “注释”也是JDK5的壹个新特性,在这里使用非常合适。 有几种方法前面有@Before、@Test、@Ignore等字符,您可以看到它们是注释,以壹个“@”开头。 这些注释是在JUnit4中定制的,为了创建相应的测试类,充分理解这些注释的含义很重要。

接下来,代码创建一个测试类CalculatorTest.java,如下所示:

package net.oschina.bairrfhoinn.test;

导入静态org.JUnit.assert.*;

import org.junit.Test;

import net.oschina.bairrfhoinn.main.calculator;

公共类计算器测试{

privatestaticcalculatorcalculator=new calculator (;

@Test

公共语音测试

calculator.add(7;

calculator.add(8;

assertequals(15,calculator.getReuslt );

}

}

首先,在方法之前使用@Test标记表示这是一个测试方法。 方法声明可以自由命名,没有限制,但返回值必须是void,没有参数。 如果违反这些规定,运行时将抛出一个异常。 关于方法内应该写什么,取决于需要测试什么。 例如,在上面的代码中,如果要测试壹下的add ) )方法的功能是否正确,请在测试方法中调用add函数几次。 初始值为0,如果首先添加7,然后添加8,则预期结果应该为15。 如果最终的实际结果仍然是15,则add ()方法是正确的,反之亦然。 assertequals(15,calculator.getResult ); 用于判断期望结果和实际结果是否相等。 其中,在第一个参数中填写期望结果,在第二个参数中填写实际结果。 也就是说,是通过计算得到的结果。 这样写的话,JUnit会自动进行测试,并将测试结果反馈给用户。

想想看

运行它,可以在 eclipse 的资源管理器中选择该类文件,然后点击右键,选择 Run As->JUnit Test 即可看到运行结果。

使用@Test 的属性 Ignore 指定测试时跳过这个方法

如果在写程序前做了很好的规划,那么哪些方法是什么功能都应该实现并且确定下来。因此,即使该方法尚未完成,他的具体功能也是确定的,这也就意味着你可以为他编写测试用例。但是,如果你已经把该方法的测试用例写完,但该方法尚未完成,那么测试的时候无疑是“失败”。这种失败和真正的失败是有区别的,因此 JUnit 提供了壹种方法来区别他们,那就是在这种测试函数的前面加上 @Ignore 标注,这个标注的含义就是“某些方法尚未完成,暂不参与此次测试”。这样的话测试结果就会提示你有几个测试被忽略,而不是失败。壹旦你完成了相应函数,只需要把@Ignore标注删去,就可以进行正常的测试。

比如说上面的测试类 Calculator.java 中,假设我们的 Calculator 类的 multiply() 方法没有实现,我们可以在测试类 CalculatorTest 中先写如下测试代码:

package net.oschina.bairrfhoinn.test;

import static org.junit.Assert.*;

import org.junit.Ignore;

import org.junit.Test;

import net.oschina.bairrfhoinn.main.Calculator;

public class CalculatorTest {

private static Calculator calculator = new Calculator();

... //此处代码省略

@Ignore("method square() not implemented, please test this later...")

@Test

public void testSquare(){

calculator.square(3);

assertEquals(9, calculator.getReuslt());

}

}

我们再运行壹次测试,会看到如下结果,从图中可以很明显的看出,方法testSquare() 上的 @Ignore 注解已经生效了,运行时直接跳过了它,而方法testAdd()仍然正常的运行并通过了测试。

使用注解 @Before 和 @After 来完成前置工作和后置工作

前置工作通常是指我们的测试方法在运行之前需要做的壹些准备工作,如数据库的连接、文件的加载、输入数据的准备等需要在运行测试方法之前做的事情,都属于前置工作;类似的,后置工作则是指测试方法在运行之后的壹些要做的事情,如释放数据库连接、输入输出流的关闭等;比如我们上面的测试,由于只声明了壹个 Calculator 对象,他的初始值是0,但是测试完加法操作后,他的值就不是0了;接下来测试减法操作,就必然要考虑上次加法操作的结果。这绝对是壹个很糟糕的设计!我们非常希望每壹个测试方法都是独立的,相互之间没有任何耦合度。因此,我们就很有必要在执行每壹个测试方法之前,对Calculator对象进行壹个“复原”操作,以消除其他测试造成的影响。因此,“在任何壹个测试方法执行之前必须执行的代码”就是壹个前置工作,我们用注解 @Before 来标注它,如下例子所示:

package net.oschina.bairrfhoinn.test;

...

import org.junit.After;

import org.junit.Before;

import org.junit.Ignore;

import org.junit.Test;

public class CalculatorTest {

...//这里省略部分代码

@Before

public void setUp() throws Exception {

calculator.clear();

}

@After

public void tearDown() throws Exception {

System.out.println("will do sth here...");

}

...//这里省略部分代码

}

另外要说的是,注解 @Before 是定义在 org.junit.Before 这个类中的,因此使用时需要将其引入我们的代码中。这样做了之后,每次我们运行测试方法时,JUnit 都会先运行 setUp() 方法将 result 的值清零。不过要注意的是,这里不再需要 @Test 注解,因为这并不是壹个 test,只是壹个前置工作。同理,如果“在任何测试执行之后需要进行的收尾工作,我们应该使用 @After 来标注,方法与它类似。由于本例比较简单,不需要用到此功能,所以我们只是简单了给它添加了壹个 tearDown() 方法并在收尾时打印壹句话到控制台,并且使用 @After 来注解这个方法。

使用@BeforeClass 和 @AfterClass 来完成只需要执行壹次的前置工作和后置工作

上面我们提到了两个注解 @Before 和 @After ,我们来看看他们是否适合完成如下功能:有壹个类负责对大文件(超过500 MB)进行读写,他的每壹个方法都是对文件进行操作。换句话说,在调用每壹个方法之前,我们都要打开壹个大文件并读入文件内容,这绝对是壹个非常耗费时的操作。如果我们使用 @Before 和 @After ,那么每次测试都要读取壹次文件,效率及其低下。所以我们希望的是,在所有测试壹开始读壹次文件,所有测试结束之后释放文件,而不是每次测试都读文件。JUnit的作者显然也考虑到了这个问题,它给出了@BeforeClass 和 @AfterClass 两个注解来帮我们实现这个功能。从名字上就可以看出,用这两个注解标注的函数,只在测试用例初始化时执行 @BeforeClass 方法,当所有测试执行完毕之后,执行 @AfterClass 进行收尾工作。在这里要注意壹下,每个测试类只能有壹个方法被标注为 @BeforeClass 或 @AfterClass,而且该方法必须是 public static 类型的。

使用@Test 的属性 timeout 来完成限时测试,以检测代码中的死循环

现在假设我们的 Calculator 类中的 square() 方法是个死循环,那应该怎么办呢,比如说像下面这样:

public void square(int n){

for(;;){}

}

如果测试的时候遇到死循环,你的脸上绝对不会露出笑容的。因此,对于那些逻辑很复杂,循环嵌套比较深的、有可能出现死循环的程序,因此壹定要采取壹些预防措施。限时测试是壹个很好的解决方案。我们给这些测试函数设定壹个预期的执行时间,超过了这壹时间,他们就会被系统强行终止,并且系统还会向你汇报该函数结束的原因是因为超时,这样你就可以发现这些 Bug 了。要实现这壹功能,只需要给 @Test 标注加壹个参数timeout即可,代码如下:

@Test(timeout=2000L)

public void testSquare() {

calculator.square(3);

assertEquals(9, calculator.getReuslt());

}

timeout参数表明了你预计该方法运行的时长,单位为毫秒,因此2000就代表2秒。现在我们让这个测试方法运行壹下,看看失败时是什么效果。

使用@Test 的属性expected来监控测试方法中可能会抛出的某些异常

JAVA中的异常处理也是壹个重点,因此你经常会编写壹些需要抛出异常的函数。如果你觉得壹个函数应该抛出异常,但是它没抛出,这算不算 Bug 呢?这当然是Bug,JUnit 也考虑到了这壹点,并且可以帮助我们找到这种 Bug。例如,我们写的计算器类有除法功能,如果除数是壹个0,那么必然要抛出“除0异常”。因此,我们很有必要对这些进行测试。代码如下:

@Test(expected=java.lang.ArithmeticException.class)

public void testDivide(){

calculator.divide(0);

}

如上述代码所示,我们需要使用@Test注解中的expected属性,将我们要检验的异常(这里是 java.lang.ArithmeticException)传递给他,这样 JUnit 框架就能自动帮我们检测是否抛出了我们指定的异常。

指定 JUnit 运行测试用例时的 Runner

大家有没有想过这个问题,糟糕的大叔把测试代码提交给JUnit框架后,框架是如何来运行你的代码的呢?答案就是Runner。在JUnit中有很多个Runner,他们负责调用你的测试代码,每壹个Runner都有其各自的特殊功能,你要根据需要选择不同的Runner来运行你的测试代码。可能你会觉得奇怪,前面我们写了那么多测试,并没有明确指定壹个Runner啊?这是因为JUnit中有壹个默认的Runner,如果你没有指定,那么系统会自动使用默认Runner来运行你的代码。换句话说,下面两段代码含义是完全壹样的:

import org.junit.runner.RunWith;

import org.junit.runners.JUnit4;

@RunWith(JUnit4.class)

public class CalculatorTest {

...//省略此处代码

}

//用了系统默认的JUnit4.class,运行效果完全壹样

public class CalculatorTest {

...//省略此处代码

}

已赞过

已踩过<

你对这个回答的评价是?

评论

收起

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。