Java如何写一个好的单元测试

单元测试的目的?

单元测试是编写测试代码,用以检测特定的、明确的、细颗粒的功能!
严格来说,单元测试只针对功能点进行测试,不包括对业务流程正确性的测试。
现在一般公司都会进行业务流程的测试,这也要求测试人员需要了解需求!
测试人员也不好过啊~~

目前开发所用的单元是Junit框架,在大多数java的开发环境中已经集成,可以方便开发自己调用!

注意:单元测试不仅仅是要保证代码的正确性,一份好的单元测试报告,还要完整地记录问题的所在和缺陷以及正确的状态,方便后面代码的修复,重构和改进。

单元测试做什么?

一般来说,一份单元测试主要包括以下几个方面:

1. 接口功能性测试: 接口功能的正确性,即保证接口能够被正常调用,并输出有效数据!

  • 是否被顺利调用
  • 参数是否符合预期

2. 局部数据结构测试:保证数据结构的正确性

  • 变量是否有初始值或在某场景下是否有默认值
  • 变量是否溢出

3. 边界条件测试:测试

  • 变量无赋值(null)
  • 变量是数值或字符
  • 主要边界:最大值,最小值,无穷大
  • 溢出边界:在边界外面取值+/-1
  • 临近边界:在边界值之内取值+/-1
  • 字符串的边界,引用 "变量字符"的边界
  • 字符串的设置,空字符串
  • 字符串的应用长度测试
  • 空白集合
  • 目标集合的类型和应用边界
  • 集合的次序
  • 变量是规律的,测试无穷大的极限,无穷小的极限

4. 所有独立代码测试:保证每一句代码,所有分支都测试完成,主要包括代码覆盖率,异常处理通路测试

  • 语句覆盖率:每个语句都执行到了
  • 判定覆盖率:每个分支都执行到了
  • 条件覆盖率:每个条件都返回布尔
  • 路径覆盖率:每个路径都覆盖到了

5.异常模块测试,后续处理模块测试:是否包闭当前异常或者对异常形成消化,是否影响结果!

Java的单元测试Junit4

1. 业务流程的一般是按照需求的预期效果,跑完整个业务流程,包括以前开发的流程

  • 是否实现了预期
  • 是否影响到了以前的流程
  • 全流程是否顺利
  • 数据是否符合预期

2. 代码测试:

// 全局只会执行一次,而且是第一个运行
@BeforeClass 
// 在测试方法运行之前运行
@Before 
// 测试方法
@Test 
// 在测试方法运行之后允许
@After 
// 全局只会执行一次,而且是最后一个运行
@AfterClass 
// 忽略此方法
@Ignore 

JUNIT4是以org.junit为框架进行的测试,以注解的形式来识别代码中需要测试的方法!

注意:
对于每一个测试,我们都应该保持独立测试,以确保测试结果是有意义的。
在程序中,经常会出现,当测试完一个方法后,其参数已经被系统保持或持久化下来。
无疑会造成下一次的测试测试数据或者状态的不合理性!
为了解决问题,对于此类场景,我们的测试代码必须具备初始化和收尾的能力。
也即是@Before和@After的意义所在!
@Before可以在测试之前准备需要的数据
@After可以在@Test方法运行之后把测试数据删除
同理@AfterClass和BeforeClass即是为了满足测试中,那些体积非常大,但只要一次初始化的代码块!

3. 断言测试与及常用断言:

  • assertEquals:
Assert.assertEquals("此处输出提示语", 5, result);

解析:
"此处输出提示语": 为错误时你个人想要输出的错误信息;
5: 是指你期望的值;
result: 是指你调用程序后程序输出给你的结果

  • 有些异常是我们预期的, 不希望测试抛异常, 那又该怎么做呢
@Test(expectedExceptions = NullPointerException.class)  

解析:在注解的时候添加expectedExceptions 为忽略此异常

  • 超时设置:
@Test(timeout  =   5000 )
  • 期望出现异常,如果出现该异常则成功,否则测试失败
@Test(expected  =  XXXXException. class)
  • 用户方法之上,被注解的方法会被成功需忽略
@Ignore() 
  • 判断测试失败
fail("Not yet implemented")

解析:放在方法中,如果我顺利地执行,我就报失败出来。就是说按道理不应该执行到这里的,但是偏偏执行了,说明程序有问题

  • 断言结果是真的或者结果是假的
// 断言结果是真的
Assert.assertTrue("msg",boolean)
// 断言结果是假的
Assert.assertFalse("msg",boolean)

解析:如果和预期一样为true则成功,否则失败输出msg;如果和预期一样为false则成功,否则失败并输出

  • 断言结果是null
assertNull("msg",boolean)与assertNotNull("msg",boolean)

解析:assertNull与assertNotNull可以验证所测试的对象是否为空或不为空,如果和预期的相同则测试成功,否则测试失败!
4. 主要常用方法

断言列表:

断言语句 要求
assertTrue(String message, boolean condition) condition == true
assertFalse(String message, boolean condition) condition == false
assertEquals(String message, XXX expected,XXX actual) expected期望的值能够等于actual
assertArrayEquals(String message, XXX[] expecteds,XXX [] actuals) expected.equalsArray(actual)
assertNotNull(String message, Object object) object!=null
assertNull(String message, Object object) object==null
assertSame(String message, Object expected, Object actual) expected == actual
assertNotSame(String message, Object unexpected,Object actual) expected != actual
assertThat(String reason, T actual, Matcher matcher) matcher.matches(actual) == true
fail(String message) 执行的目标结构必然失败,同样要求代码不可达,即是这个方法在程序运行后不会成功返回,如果成功返回了则报错

5. 运行器指定?

单元测试中,每个类都是由于JUNIT4框架中的Runner运行器来执行的。一般情况下,在没有指定运行器的时候,是由系统默认选择(TestClassRunner)的运行器执行。包括类中的所有方法都是由该运行器负责调用和执行。当我们需要指定的时候,则通过类级别注解 @Run Wirth(xxxxxx)进行选择,一般是根据不同类型选择不同执行器,可以提高效率也可以应用于某种特殊场景!

6. 参数化测试?

 @RunWith(Parameterized. class )
 public class TestParam {
      private static Calculator calculator = new Calculator(); //需要测试的类
      private int param; 
      private int result;
 
      @Parameters
      public static Collection data(){
        return Arrays.asList(new Object[][] {{11, 17} , {xx1, xx}});
      } 

      //有参构造,在实例的时候实现参数初始化
      public TestParam(int param, int result){
        this .param = param;
        this .result = result;
      } 
 
      @Test
      public void TestResult(){
       calculator.square(param);
       assertEquals(result, calculator.getResult()); 
      }  
} 

解说:参数化测试的目标是为了一次性完成同类型测试,将相同类型的数据按照一定的顺序批量地传入测试方法,并得出结论!其本质是一个批量的化的操作,只是为了方便我们测试而进行了封装。我们只有提供测试的方法以及按照一定的顺序进行设置则可以。

进行类注解:@RunWith(Parameterized.class),为了测试类指定一个ParameterizedRunner运行器

进行参数设置:将测试结果和期望结果,以每一组都是一个数组的形式存放以形成二维数组,转化为list返回并注解。

参数初始化:设置测试方法要入参的参数,并按照"参数设置"的顺序利用构造方法进行初始化的赋值!

测试调用:写一个测试方法进行调用,将参数传递到要测试的类的方法中并返回数据

注意:参数化测试需要创建一单独用于测试的测试类。并定义两个变量用于接受测试结果和预期目标。数据存放以二维数组的方式,两个为一组。接着便是通过构造方法进行数据初始化。 构造方法入参的顺序要和二维数组中国每一组存放的数据顺序保持一致。

7. 打包测试

@RunWith(Suite. class )
@Suite.SuiteClasses( {CalculatorTest. class ,SquareTest. class } )
public   class  AllCalculatorTests  {
    //to do something;
} 

解析:将有需要的一起执行程序一起打包,然后执行
运行器:Suite. class
解析:我们把需要打包一起测试的测试类作为参数传递给该注解。然后直接运行代码,此处的测试类可以直接设置为空,只需要添加注解便OK;

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,490评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,581评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,830评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,957评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,974评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,754评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,464评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,357评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,847评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,995评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,137评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,819评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,482评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,023评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,149评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,409评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,086评论 2 355

推荐阅读更多精彩内容