JUnit单元测试,既然叫单元,那就是针对最小功能单元来说,也就是针对单个方法的测试,像Python里的unittest,比如OpenStack对应的Tempest都是由一个一个单元测试构成的,Java的JUnit也基本类似
常规也是通过Assert断言来书写测试代码来测试结果的正确性
在IDEA里需要安装JUnit插件,搜junit即可;当然如果配置了Maven,直接就有
简单写一个例子进行下单元测试,比如写了一个求和的方法,用了递归
package match.pattern; /** * @author lihui * @date 2018/3/30 16:06 */ public class Match { public long sum(int x) { if (x == 0) { return 0; } else { return x + sum(x - 1); } } }
正常情况下,写完了实现代码之后,就要写一些对应的测试代码
在需要测试的当前类下鼠标右键Go To,然后选择Test,Create New Test…
到了这个窗口:
Testing library:根据你当前配置的JUnit版本一致,我这里用的是Maven里4.12版本,因此这里library选择JUnit4
Class name:基本所有单元测试都是需要携带Test关键字,区别就是大小写以及位置不同,这里需要单元测试的方法所在的类是Match,因此添加单元测试的类就是MatchTest
Superclass:这里选择你使用的junit里frameword里TestCase作为超类
Destination package:包名,和需要测试的方法所在的包一致,不需要修改,默认就行了
Generat:setUp是测试前一些初始化工作;tearDown是测试后的清理,垃圾回收工作
最下面Member里就是需要单元测试的方法,这里只有一个sum
最终配置如下:
这样对应在Maven对应的test目录下,生成了一个match.pattern包以及MatchTest类,内容如下
package match.pattern; import junit.framework.TestCase; import org.junit.After; import org.junit.Before; import org.junit.Test; import static org.junit.Assert.*; /** * @author lihui * @date 2018/3/30 17:05 */ public class MatchTest extends TestCase { @Before public void setUp() throws Exception { } @After public void tearDown() throws Exception { } @Test public void sum() { } }
装饰器@Test下的方法就是我们需要添加测试代码的方法,setUp和tearDown这里就打印一些信息
package match.pattern; import junit.framework.TestCase; import org.junit.After; import org.junit.Before; import org.junit.Test; import static org.junit.Assert.*; /** * @author lihui * @date 2018/3/30 17:05 */ public class MatchTest extends TestCase { @Before public void setUp() throws Exception { System.out.println("setUp"); } @After public void tearDown() throws Exception { System.out.println("tearDown"); } @Test public void sum() { assertEquals(5050, new Match().sum(100)); } }
测试0一直加到100的和正确性,运行结果报了一个错误
测试未生效,原因是编写的测试方法sum不对,需要添加test
@Test public void testSum() { assertEquals(5050, new Match().sum(100)); }
修改成testSum,执行就没问题了
再来考虑,对于测试需要验证哪些地方,比如sum方法返回值是long,那么返回值越界问题?参数x的边界值?越界?等等,都是需要测试的
比如这里以100,0,-100为例测试一下
@Test public void testSum() { assertEquals(5050, new Match().sum(100)); assertEquals(0, new Match().sum(-100)); assertEquals(0, new Match().sum(0)); }
测试的结果,第12行出错
显然当x为-100的时候,这个递归就持续减1,没法结束了,实现时可能只考虑了从0开始算,因此这里将sum方法修改一下,当x <= 0,都返回0即可
package match.pattern; /** * @author lihui * @date 2018/3/30 16:06 */ public class Match { public long sum(int x) { if (x <= 0) { return 0; } else { return x + sum(x - 1); } } }
这里有一个地方要注意一下,如果添加一个@Test方法
@Test
public void testSum() {
assertEquals(5050, new Match().sum(100));
assertEquals(0, new Match().sum(-100));
}
@Test
public void testZero() {
assertEquals(0, new Match().sum(0));
}
那么setUp和tearDown就执行了两次;也就是说,每一个@Test方法执行之前,都会新创建一个MatchTest实例,,在@Test的前后分别执行@Before和@After各一次
上面这段简单举例的代码连很简单的单元测试都没通过,属于基本的坑,这里只是举一个例子,真正系统测试当中,不光要进行正常功能验证,还要根据开发实现的代码进行单元测试,当然最终是要在看懂开发代码的基础上,考虑一些逻辑关系以及可能存在的坑的情况下,写测试代码,才算完美