junit进行单元测试
Junit目前在一些大的公司或者相对规范的软件中使用的比较多,相当多的小公司并没有把单元测试看的太重要。在大点的公司开发人员每天上班后,第一件事情就是从svn上把自己负责的代码checkout下来,然后运行单元测试,如果单元测试通过,那么说明自己的代码没有问题,然后就在代码块上修改与添加,完成后再用junit进行测试,测试完成后如果没有问题,那么就把相应的代码块提交给svn上。
在以前的的项目中也用过Junit,当时的使用只是把Junit当成一个有多个main方法的一个函数。假如一个项目非常的大,测试的东西非常的多,如果不用Junit的话,那么这个工作量是非常大的。单元测试的最基本的一个功能是能进行自动化测试。单元测试都是通过断言的方式来确定结果是否正确,即使用Assert。
junit3与junit4的区别还是比较明显的,在junit3中,如果某个类是测试类,必须将其继承类TestCase,如果某个方法是测试方法,必须让这个方法以testXX开头,如果希望指定某个测试方法运行之前运行某个初始化方法,这个方法的名称必须是setUp,如果希望在某个测试方法运行之后运行某个释放资源的方法,这个方法的名称必须是tearDown
在junit4中,一个POJO类就是一个测试类,测试方法通过@Test来标识,初始化方法通过@Before来标识,释放资源的方法通过@After来标识,但是为了让junit4的测试类在junit3中也可以使用,习惯于把初始化方法命名为setUp,释放资源的方法命名为tearDown。Test中的测试方法一般以Test来开始。其中标识为Before注解的方法,每次运行测试类,都会执行标识为@After与@Before的方法。
在junit4中提供了一个Assert的类,这个类中有大量的静态方法进行断言的处理,在junit3中由于继承了TestCase,这个TestCase就可以直接assert,而junit4中需要先引入Assert类(就是import导入)
在上图中使用了Assert类中的assertEquals方法,这方法的第一个参数意思是:如果方法cal.add(12,22)计算的结果不为34,那么就会打印出“加法有问题”的信息。第二个参数为方法cal.add(12,22)的执行结果,第三个参数是开发人员预计的函数cal.add(12,22)执行后的结果,这里预计12与22相加后其结果为34,如果在执行测试方法后,rel不等于34,那么就会报加法有问题。如果结果等于34,那么这个方法就测试通过
如果想让上面的测试类可以在junit3中运行,可以把Assert类静态的导入,这样在调用每个静态方法时,就不用都写上Assert类了(就是 import static org.Assert.assertEquals)
使用junit测试比使用main方法测试有很大的不同的是,每个标识为@Test的方法都是一个可运行的方法,并且他们之间互不影响,例如testAddd方法出现问题了,并不影响testMinus方法的运行。这就是单元测试的好处(意思就是首先:我们要测试某一个函数,我们不需要从main函数开始运行,第二:我们的某一个函数出现错误的时候,其他的函数不会受到影响,不像只执行main函数的时候,只要出现错误就会全部崩盘)
在测试除法cal.divide(3,0),如果除数为0,这个方法应该会抛出异常。现在的测试目标是,如果运行测试方法后,测试方法没有抛出异常,那么这个测试方法就不能通过。这时就需要用到junit的ArithmeticException。如下图所示:
如图:圈住的部分:首先使用@test来声明这是一个测试方法,然后括号中声明了一个(excepted = ArithmeticException.class),这相当于直接说明这个方法是需要抛出异常的,如果没有抛出那么就直接判定测试没有通过,Junit会提示未通过的原因是没有抛出想要的异常ArithmeticException(算数异常),因此如果此时你调用testDivideException方法修改为cal.divide(20,10),此时divided方法的执行是没有问题的,但是testDivideException方法执行junit测试之后却不能通过,因为此时这个测试方法已经断言所要测试的方法divide要抛出异常,结果却没有异常,所以junit认为测试的结果和预期的结果不同,所以不能通过
有时在测试时需要有这样的需求,就是对一个方法的时间进行测试,例如,要让一个方法,200毫秒里运行完,如果这个方法200毫秒不能运行完,那么这个方法就应该抛出异常,示例中将方法time中线程沉睡300毫秒,那么这个方法就不可能在200毫秒内完成,所以这个方法就会抛出异常。这就可以做一些方法性能上的测试,把Thread去掉,那么这个测试就可正常通过。如下图所示:
Junit的最基本的东西基本是这样的,断言、测试异常,捕获异常,测试方法的性能
junit学习之hamcrest、testSuite介绍及测试原则
上一节说了junit的一些基本概念,主要使用assert做一些基本的判断。但很多时候使用assert做判断,并不方便,如果要判断某几个值是否为true或false,这时使用hamcrest来判断就会方便许多。hamcrest就是专门为增强junit来提供的框架。它可以有效的使用一些语义比较清楚的名字来做判断,一些常用的方法如下:
下面使用hamcrest在上一节的例子上继续操作。使用junit中的assertThat进行断言,第一个参数为实际值,第二个参数为hamcrest的表达式。
在上一节的测试类TestCalcuate中,先静态导入hamcrest包中的Matchers类,)下面使用hamcrest在上一节的例子上继续操作。使用junit中的assertThat进行断言,第一个参数为实际值,第二个参数为hamcrest的表达式。
在上一节的测试类TestCalcuate中,先静态导入hamcrest包中的Matchers类,(import static org.hamcreast.Matchers.*;)
2、 添加下图所示的测试方法,在测试方法testHamcrest方法中,把junit与hamcrest结合使用,方法assertThat方法是junit的方法,greaterThan方法是hamcrest的方法,greaterThan判断第一个参数是否>第二个参数,这里就是判断50是否大于20。
@Test
public void testHamcrest(){
assrtThat(50,greaterThan(20));
//assertThat是junit的方法,greaterThan是hamcrest的方法,用来判断第一个参数是否大于第二个参数
}
3、如果要判断第一个参数是否大于20,并且小于60,这时可以使用正面的方式:
@test
public void testHamcreast(){
assertThan(50,allof(greatThan(49),lessThan(60)));
//allof代表的是执行口号里面的所有判断
}
4、这时使用junit进行测试,如果测试通过,代表50确实大于49,小于60,如果出现如下错误:
5、其原因是因为资源路径里junit的jar包在hamcrest的jar包上面,java运行环境先从junit包中查找allOf方法,但是这里使用的是hamcrest的allOf方法。从资源路径里把两个包的路径换一下就可以了。如下图,选择hamcrest的jar包点击up,就可以反hamcrest的jar包放在junit的jar包的上面,java运行环境就会优先从hamcrest包中查allOf方法。
6、使用hamcrest还可以判断一个字符串是否以某个字符串开始或结尾。
@test
public void testHamcrestEndWith(){
assertThat(“like.txt,endsWith(“txt”));
}
7、在一个项目中,可能有很多的测试类,如果每个测试类都要点击运行,那么成百上千个类都需要测试,这会是个比较繁重的工作,这时可以使用可以使用junit的jar包中提供的Suite来解决这个问题,例如新建两个测试类,分别为TestA、TestB,
8、然后新建一个测试类TestSuite,这个类可以把以上三个类,TestCalcuate、TestA、TestB,这三个测试方法同时进行测试。如下所示,
@RunWith(Suite.class)//代表以suite来运行这个测试类
//代表要测试哪些类
@SuiteClasses({TestA.class,TestB.class,TestClacuate.class})public class testSuite{
public void testSuite(){
System.out.println(“TestA”);
}
}
如上操作完成后点击运行,就可以看到所有的测试方法全通过的信息
测试原则:
1、建议创建一个专门的source folder—>test来编写测试类代码。上面例子就新建一个test的资源包。就是说必须要保证测试代码和功能代码的分离
2、测试类的包应该保持和需要测试的类一致。上面的例子中Calcuate类在src/cn/whp/util包中,相应的测试类就在test/cn/whp/util中。这样才能保证Junit工具运行正常
3、测试单元中的每个测试方法都必须可以独立执行,不相互依赖,没有顺序。
这也是最大的一个问题,例如应用中的许多方法都是依赖上下文的或者说,这个方法在不同的时候,可能因为其他对象或者属性的变化,而导致此方法返回值不同(或者说其方法得正确得结果不唯一),这样的话就必须要修改测试用例来适应这种变化(所以需要学习函数式编程的思想