JUnit4-单元测试提高篇

Catalog 

Test Fixture 

参数化测试

Runner运行器

 

Test Fixture

Test Fixture 有人叫它测试设备,有人说它是固定的代码段,我不知道该怎么称呼它,

但是它的英文的解释是: The test fixture is everything we need to have in place to exercise the  SUT.

可以翻译为:运行被测试软件所需要的一切东西。

 

比较常见的用法:

  • 实例化某个被测方法所在的类 ,eg.  你要测试Calculator类中的Add()方法,则需要实例化Calculator类;
  • 准备连接数据库,eg. 平时写关于数据库操作时,你只会写一个连接类,大家都调用这个类,对于测试方法也是类似的道理;
  • 其他的可以自己发现...

 

准备Test Fixture方法有三种,所以一步一步进化来的,目的是减少重复的代码,节约资源。

  • 内联方式
  • 委托方式
  • 隐藏方式

 

内联方式

eg. 你要测试一个类中所有的方法,在每个方法中都写上被测试类的实例对象,即 被测试类XXX  test = new 被测试类XXX();

这样就造成了代码的重复,如果这个new 这个实例的过程非常复杂,那么也会减低测试代码的可读性和可维护性。另外一个问题是,

这种方法很容易带来测试书库Hard code的隐患(还不理解,待解答)。

不过,对于初学者,这是最简单的方法,也是单元测试的入门过程。

 

 1 public class MathDemoTest {
 2     @Test
 3     public void testAdd() {
 4         MathDemo  demo  = new MathDemo();
 5         int expetected = 1;
 6         int trueValue = demo.add(1, 1);
 7         //断言方法
 8         assertEquals("你好像写错了",expetected, trueValue);
 9     }
10     @Test
11     public void testDiv() {
12         MathDemo  demo  = new MathDemo();
13         int expected = 1;
14         int trueValue = demo.div(1, 1);
15         assertEquals(expected, trueValue);
16     }
17 }
内联方式

 

委托方式

eg. 数据库连接过程是单独的一个方法,然后需要的时候代用该方法即可。这种方式的好处就是使得测试代码可读性增强,并且

这部分的SetUp(这个对应的注解是@Before)代码可以重复使用。而且这种做法可以屏蔽对SetUp过程的认知,使得测试人员的关注

点落在真正的测试代码上面,而不是如何SetUp。

 

隐藏方式

JUnit是一个可编写重复测试的简单框架,是基于Xunit架构的单元测试框架的实例。很多的Xunit框架的实现都提供了不同的隐

式SetUp 和 TearDown 。eg. 在JUnit里面的 @Before  和 @After 注解,就提供了一种隐式准备Test Fixture的支持, 在每个

测试方法运行前,都会执行带有@Before注解的方法,在每个测试方法运行结束后,都会执行带有  @After  注解的方法。这种方式

的好处就是写一次就能在各个测试方法中都实现了 Test Fixture的准备, 不用显式的调用一个外部方法,但是也有确定:可能会令

测试比较难懂,因为这些隐式调用不是必须的,有可能被遗漏掉。

 

 1 public class MathDemoTest {
 2     MathDemo demo;    
 3     @Before
 4     public void setUp(){
 5         System.out.println("Set up ...");
 6         demo  = new MathDemo();
 7     }    
 8     @After
 9     public void tearDown(){
10         System.out.println("Done...");
11         demo = null;
12     }
13     @Test
14     public void testAdd() {
15         
16         int expetected = 1;
17         int trueValue = demo.add(1, 1);
18         //断言方法
19         assertEquals("你好像写错了",expetected, trueValue);
20     }
21     @Test
22     public void testDiv() {
23         int expected = 1;
24         int trueValue = demo.div(1, 1);
25         assertEquals(expected, trueValue);
26     }
27 
28 }
隐藏方式

 

更深入、灵活的使用隐式方式可以参考该链接下面的例子:单元测试三种TestFixture方法比较

 

@Before 和 @ After 注解是作用于测试方法的,标注的方法是public  void的,和普通的测试方法规则一样,但是对于每个测试

方法都需要执行一遍是非常费时的操作,此时,如果有一种注解可以在测试类开始和结束时只执行一次,而不是作用于每个测试方法,

这样可以节省很多时间。这两个注解就是   @BeforeClass 和  @AfterClass , 而且该方法必须是 Public static的。 

 

   一个测试类中可以出现几次                   方法要求                                   运行次数                                   
 @Before 和 @After >= 0 次  public  void 的  作用于测试方法的,有几个测试方法就运行几次
 @BeforeClass 和 @AfterClass  0次 ||  1次  public  static 的  作用于测试类的,只运行一次

 

 

public class AnnotationDemo {
    MathDemo demo;    
    @BeforeClass
    public static void setUpBeforeClass(){
        System.out.println("beforeclass  set Up..");
    }
    
    @AfterClass
    public static void tearDownAfterClass(){
        System.out.println("afterclass   Gone...");
    }
    
    @Before
    public void setUp(){
        System.out.println("Set up ...");
        demo  = new MathDemo();
    }    
    @After
    public void tearDown(){
        System.out.println("Done...");
        demo = null;
    }    
    @Test
    public void add(){
        assertEquals(2, demo.add(1, 1));
    }    
    @Test
    public void add2(){
        assertEquals(1, demo.div(1, 1));
    }
}
两种Test Fixture对比

 

上面代码的运行结果:

 

参数化测试

Parameterized:根据所设计的参数来执行测试。

eg .一个函数,参数有许多特殊值,或者参数分为很多个区域,如对考试分数进行分区,需要返回"优秀、良好、一般、及格、不及格",

因此在编写测试的时候,至少需要写5个测试,把这5种情况都包含进去,很麻烦。

eg. 假设某个需要被测试的方法,它有两个参数,每个参数需要设计不同的值,那么我们一开始是需要为每一个参数设计一个测试方法,

这样就很麻烦,10中case就需要10个方法,但是运用 Parameterized  runner , 可以设计一个方法,多种参数来执行test case。

 

 

Run运行器

 简简单单的写一个@test,其他的都不用管,JUnit框架就帮我们运行测试代码,那么框架是如何运行提交的测试代码呢?

----->Runner,在JUnit4中有很多的Runner,它们负责调用提交的测试代码,每个Runner都有自己的独特功能,所以我们可以

指定Runner来执行测试代码,在还不知道这个概念时,测试代码也是可以正常运行的,其原因是JUnit4中有一个默认的Runner

名字是BlockJUnit4ClassRunner.class ,如果没有指定Runner,系统会自动使用默认的Runner。

 

 1 public class MathDemoTest {
 2     @Test
 3     public void testAdd() {
 4         MathDemo  demo  = new MathDemo();
 5         int expetected = 1;
 6         int trueValue = demo.add(1, 1);
 7         //断言方法
 8         assertEquals("系统使用默认的Runner",expetected, trueValue);
 9     }
10 }

Vs 指定 BlockJUnit4ClassRunner.class , 这个即是JUnit4默认的Runner,效果和上面的代码一样。

 1 @RunWith(BlockJUnit4ClassRunner.class)
 2 public class MathDemoTest {
 3     @Test
 4     public void testAdd() {
 5         MathDemo  demo  = new MathDemo();
 6         int expetected = 1;
 7         int trueValue = demo.add(1, 1);
 8         //断言方法
 9         assertEquals("你好像写错了",expetected, trueValue);
10     }
11     @Test
12     public void testDiv() {
13         MathDemo  demo  = new MathDemo();
14         int expected = 1;
15         int trueValue = demo.div(1, 1);
16         assertEquals(expected, trueValue);
17     }
18 }

从上面的例子可以知道,指定Runner使用的是 @RunWith 注释,标注在测试类上,是修饰类的,作用于该测试类中的所有测试方法。

其他特殊的Runner有:

      1. Suite.class    实现打包测试
      2. Parameterized.class   实现参数化测试
      3. Categories.class
      4. Enclosed.class

 这几种Runner见随笔: JUnit4-Runner

 

 

posted @ 2015-11-13 11:44  Mokaffe  阅读(431)  评论(0编辑  收藏  举报