0


单元测试框架(JUnit和Unittest)

单元测试就是针对最小功能单元编写测试代码

1 JUnit

Unit 是一个 Java编程语言的单元测试框架,java程序最小的功能是方法,单元测试就是针对java方法的测试。测试单元中的每个方法必须可以独立测试,方法间不能有任何依赖

1.1 JUnit结构体系

在这里插入图片描述

1.2 JUnit的使用

在这里插入图片描述

1.1 测试类与测试方法

测试类一般使用 Test 作为类名的后缀;测试方法必须使用 @Test 修饰,必须使用 public void 进行修饰,不能带参数,测试方法使一般用 test 作为方法名的前缀。

一般使用单元测试会新建一个 test 目录存放测试代码,在生产部署的时候只需要将 test 目录下代码删除即可

1.2 注解

注解符号描述说明

@Test

将一个普通方法修饰成一个测试方法

@BeforeClass

static 方法 (全局只会执行一次,而且是第一个运行),在测试类中所有方法执行前执行

@AfterClass

static 方法 (全局只会执行一次,而且是最后一个运行),在测试类中所有方法执行完成后执行

@Before

会在每一个测试方法被运行前执行一次

@After

会在每一个测试方法运行后被执行一次

@Ignore

所修饰的测试方法会被测试运行器忽略

@RunWith

可以更改测试运行器 org.junit.runner.Runner

Parameters

参数化注解

packagecom.dw.service;importstaticorg.junit.Assert.*;importorg.junit.BeforeClass;publicclassDemoTest{Demo demo;publicDemoTest(){System.out.printIn("DemoTest对象初始化");}@BeforeClasspublicstaticvoidbeforeClass(){System.out.println("beforeClass方法");}@Beforepublicvoidbefore(){
        demo=new_Demo();}@TestpublicvoidtestAdd(){assertEquals("12",demo.add("9",1,2));}@Ignore// 忽略测试publicvoidtestMul(){assertEquals("26",demo.muml("8",1));}@Afterpublicvoidafter(){System.out.println("资源释放");}

1.3 断言

断言方法描述说明

void assertEquals(boolean expected, boolean actual)

检查两个变量或者等式是否平衡

void assertTrue(boolean condition)

检查条件为真

void assertFalse(boolean condition)

检查条件为假

void assertNotNull(Object object)

检查对象不为空

void assertNull(Object object)

检查对象为空

void assertSame(Object expected, Object actual)

检查两个相关对象是否指向同一个对象

void assertNotSame(Object expected, Object actual)

检查两个相关对象是否不指向同一个对象

void assertArrayEquals(expectedArray, resultArray)

检查两个数组是否相等

1.4 TestCase 测试用例

1.5 TestSuite 测试套件

测试套件就是整合多个TestCase成为以一组测试

1.5.1 RunWith和SuiteClasses注解整合

测试套件遵循以下规则:

  1. 创建一个空类作为测试套件的入口。
  2. 使用注解 org.junit.runner.RunWithorg.junit.runners.Suite.SuiteClasses 修饰这个空类。
  3. org.junit.runners.Suite 作为参数传入注解 RunWith,以提示 JUnit 为此类使用套件运行器执行。
  4. 将需要放入此测试套件的测试类组成数组作为注解 SuiteClasses 的参数。
  5. 保证这个空类使用 public 修饰,而且存在公开的不带有任何参数的构造函数
packagetest;importorg.junit.runner.RunWith;importorg.junit.runners.Suite;importorg.junit.runners.Suite.SuiteClasses;@RunWith(Suite.class)@SuiteClasses({JunitTestOne.class,JunitTestTwo.class})// 把JunitTestOne和JunitTestTwo测试类整合到测试套件中publicclassAllTests{}

1.5.2 addTestSuite方法整合

importjunit.framework.TestResult;importjunitframework.TestSuite:publicclassAllTest{publicstaticvoidmain(Stringl args){TestSuite testSuite =newTestSuite();
        testSuite.addTestSuite(StudentTest01.class);
        testSuite.addTestSuite(StudentTest02.class);
        testSuite.run(newTestResult());}

1.6 其他测试

1.6.1 异常测试

Junit 用代码处理提供了一个追踪异常的选项, @Test 注释和expected 参数一起配合使用会对测试方法中抛出的异常做流程控制。

语法:

@Test(expected=异常名.class) 

功能描述: 只有抛出符合异常才通过测试

1.6.2 超时测试

Junit 提供了一个暂停的方便选项,@Test 注释和timeout 参数一起配合使用会对测试方法运行时间做流程控制。

语法:

@Test(timeout=N) 

N为整数,单位为毫秒
功能描述: 如果测试方法执行时间小于超时设置的时间,测试通过,反之测试不通过。

1.6.3 参数化测试

Junit 4 引入了一个新的功能参数化测试,遵循 5 个步骤来创建参数化测试。

  • @RunWith(Parameterized.class) 来注释 test 类。
  • 创建一个由 @Parameters 注释的公共的静态方法,它返回一个对象的集合(数组)来作为测试数据集合。
  • 创建一个公共的构造函数,它接受和一行测试数据相等同的东西。
  • 为每一列测试数据创建一个实例变量。
  • 用实例变量作为测试数据的来源来创建你的测试用例。

一旦每一行数据出现测试用例将被调用。让我们看看活动中的参数化测试。

@RunWith(Parameterized.class)publicclassDemoTest{int inp;int exp;publicDemoTest(int inp,int exp){this.inp=inp;this.exp=exp;}@ParameterspublicstaticCollectiondata(){returnArrays.asList(newObject[][]{(0,16},(1,24,{96,2}// 如果传入三个数则需要构造函数中传入三个参数});}@testpublicvoidtestAdd(){assertEquals(this.exp,newDemo().add(this.inp,13));}

1.7 TestRunner

测试用例是使用 JUnitCore 类来执行的,JUnitCore 是运行测试的外观类或入口类

importorg.junit.runner.JUnitCore;importorg.junit.runner.Result;importorg.junit.runner.notification.Failure;publicclassTestRunner{publicstaticvoidmain(String[] args){Result result =JUnitCore.runClasses(TestJunit.class);for(Failure failure : result.getFailures()){System.out.println(failure.toString());}System.out.println(result.wasSuccessful());}}

2 Unittest

Unittest的执行流程:

  1. 编写带有测试方法的TestCase类
  2. 通过显式或隐式方式调用TestLoader来加载要执行的TestCase类,加载完成后再添加到Testsuite 容器中
  3. 使用TestRunner来执行TestSuite中的测试用例

2.1 TestFixture 测试夹具

TestFixture是用来提供一组测试用例共用环境,使用setUp和tearDown方法将每个测试用例封装起来,保证两个测试用例之间的独立性。
调用run()方法或unittest.main()会依次调用setUp()、测试用例方法和tearDown()方法。

2.1.1 setUp() 、setUpClass()与setUpModule()

setUp() 、setUpClass()与setUpModule()用于设置环境初始化,一般用于url的访问或浏览器的打开

1、setUp()

语法:

setUp(self){代码块}

功能描述: 在每个测试用例方法执行前执行
声明位置: 定义在测试类中

2、setUpClass()

语法:

setUpClass(cls){代码块}

功能描述: 在每个测试类执行前执行
声明位置: 定义在测试类中

3、setUpModule()

语法:

setUpModule(){代码块}

功能描述: 在每个测试模块执行前执行
声明位置: 定义在测试类外

2.1.2 tearDown()、tearDownClass()与tearDownModule()

1、tearDown()

语法:

tearDown(self){代码块}

功能描述: 在每个测试用例方法执行完成后执行
声明位置: 定义在测试类中

2、tearDownClass()

语法:

tearDownClass(cls){代码块}

功能描述: 在每个测试类执行完成后执行
声明位置: 定义在测试类中

3、tearDownModule()

语法:

tearDownModule(){代码块}

功能描述: 在每个测试模块执行完成后执行
声明位置: 定义在测试类外

2.2 TestCase 测试用例

用户自定义的测试类,必须继承unittest.TestCase,

2.2.1 测试用例方法

必须使用test作为前缀,不然程序无法识别为测试用例方法

1、 装饰器

装饰器描述说明

@unittest.skip("描述说明")

跳过这条测试

@unittest.skipIf(表达式,"描述说明")

如果条件为真,那么这个用例不会参与运行。

@unittest.skipUnless(表达式,"描述说明")

如果条件为假,那么这个用例不会参与运行。

@unittest.expectedFailure("描述说明") 

标记该测试预期为失败 ,如果该测试方法运行失败,则该测试不算做失败

2、 数据驱动

(1)subTest
subTest是unittest自带,无需再安装依赖, 使用subTest可以让我们unittest的测试用例支持数据驱动的测试方法

def test**(self):
    data=(1,2,3)for d in data:with self.sunTest(data=d):
            self.asserEqual(1,d)

(2)ddt
ddt需要安装第三方库

from ddt import ddt,data,upack,file_data
import unittest
@ddtclassTestDemo(unittest.TestCase):@data(1,2,3)// 如果data中的数据是可迭代的数据时,可以使用@unpack来解构  
    def test**(self,value):
        self.asserEqual(1,value,"判断1和预期结果相等")classTestDemo01(unittest.TestCase):@file_data("data.json")// 可以传入json和yaml文件
    @unpackdef test**(self,value1,value2):
        self.asserNotEqual(value1,value2,"判断1和预期结果相等")

@data修饰器读取txt文件数据也可以使用该方法:

@data(*readText("data.txt"))
yaml文件的格式如下:
case0:
    value1:1
    value2:6
case1:
    value1:1
    value2:6

2.3 清理函数

清理函数是在

tearDown()

之后执行的函数,以清理测试期间使用的资源。

python3.1后新增的功能

addCleanup

doCleanups

方法,python3.9新增功能

addClassCleanup

doClassCleanups

方法

清理函数一般定义在测试类外,额外单独一个方法。

2.3.1 addCleanup 和 addClassCleanup

语法:

self.addCleanup(function, *args, **kwargs)

|self.addClassCleanup(function, *args, **kwargs)
功能描述: 添加清理函数function
注意:
1.如果没有

doCleanups

函数运行则会在所在的方法内执行,且在

tearDown

执行完毕后执行
2.

setUp

tearDown

哪个出现异常没有执行,照样会执行清理函数

2.3.2 doCleanups 和 doClassCleanups

语法:

self.doCleanups()

|

self.doClassCleanups()

功能描述: 运行addCleanup添加的所有清理函数
注意: 清理函数在doCleanups方法所在的位置的

tearDown

执行完毕后执行

2.4 TestLoader

1、创建一个TestLoader 实例

语法: unittest.defaultTestLoader
功能描述: 创建一个TestLoader 实例

2、加载模块

语法: TestLoader 实例.loadTestsFromModule(Module名)
功能描述: 加载模块

3、加载指定名

语法: TestLoader 实例.loadTestsFromName(Module名|测试类名|测试方法) | TestLoader 实例.loadTestsFromNames([测试类名,模块名,方法名])
功能描述: 加载一个或多个指定名的测试模块或类或方法 ;

4、discover 方法

语法: TestLoader 实例.discover(start_dir=“.”,pattern=“test*.py”)
功能描述: 加载所有符合正则表达式的测试文件

2.5 Testsuite 测试套件

测试用例集合,通过addTest()方法手动增加TestCase,也可通过TestLoader自动添加TestCase, TestLoader在添加用例时,会没有顺序。

2.5.1 addTest 整合测试用例

1、创建一个TestSuite实例

语法:

unittest.TestSuite()

功能描述: 创建一个TestSuite实例

2、添加测试用例

功能: TestSuite实例.addTest(“测试用例方法”)
功能描述: 添加测试用例

2.5.2 TestLoader 整合所有测试用例

1、创建一个TestSuite实例

语法:

unittest.TestSuite()

功能描述: 创建一个TestSuite实例

2、添加测试用例

功能:

TestSuite实例.addTest(unittest.defaultTestLoader.discover(start_dir=".",pattern="test*.py"))

功能描述: 添加测试用例

2.6 TestRunner

运行测试用例的驱动类,可以执行TestCase, 也可执行TestSuite。执行后TestCase
和TestSuite 会自动管理TestResult。

2.6.1 创建一个TextTestRunner 实例

语法: unittest.TextTestRunner()
功能描述: 创建一个TextTestRunner实例

2.6.2 执行测试套件

语法: TextTestRunner实例.run(测试套件名)
功能描述: 启动TestRunner

2.7 运行结果与测试报告

2.7.1 运行结果

符号描述说明符号描述说明

.

测试通过

F

测试失败

s

跳过测试

x

预期失败

u

意外成功

2.7.2 测试报告

1、Html测试报告
使用第三方库HTMLTestRunner

import unittest
from utils.HtmlTestRunner import HTMLTestRunner
suite=unittest.TestSuite()
cases=unittest.defaultTestLoader.discover(start_dir=".",pattern="test*.py")# 自动搜索测试用例文件
suite.addTest(cases)withopen("测试报告.html","wb")as f:
    runner=HTMLTestRunner(stream=f)
    runner.run(suite)

2.8 smtplib 邮件

import smtplib
from  email.mime.text import MIMEText
from  email.header import Header
from email.mime.multipart import MIMEMultipart
defsendEmail(to_addr,filename):
    content=MIMEMultipart()
    files=MIMEText(open(filename,"rb").read(),"base64","utf-8")
    files["Content-Type"]="application/octet-stream"
    files["Content-Disposition"]="attachment;filename=testReport.html"
    content.attach(files)
    content["From"]=Header("userName","utf-8")
    content["Subject"]=Header("emailTitle","utf-8")
    client=smtplib.SMTP()
    client.connect("邮箱地址",25)
    client.login("账号","密码")
    client.sendmail("收件邮箱",to_addr,content.to_string())

2.9 框架结构

2.9.1 框架文件结构

./case 存放测试用例类
./data 存放测试数据
./obj 存放selenium二次封装的类
./reports 存放报告
./utils 存放工具包

标签: 单元测试 junit java

本文转载自: https://blog.csdn.net/qq_42310467/article/details/129582587
版权归原作者 just表面兄弟 所有, 如有侵权,请联系我们删除。

“单元测试框架(JUnit和Unittest)”的评论:

还没有评论