JUnit 注解@RunWith的工作原理
In order to introduce the usage of this annotation in JUnit, I use an example to demonstrate.
I have a very simple price calculator:
public class PriceCalculator {
private int quantity;
private double unitPrice;
private double discount;
public PriceCalculator(int quantity, double price, double discount){
this.quantity = quantity;
this.unitPrice = price;
this.discount = discount;
}
public double getPrice(){
return this.quantity * this.unitPrice * ( this.discount / 100 );
}
}
Test class for this calculator:
import static org.junit.Assert.assertEquals;
import org.junit.Test;
public class RunWithOneTestCase {
private final static int QUANTITY1 = 5;
private final static double PRICE1 = 10;
private final static double DISCOUNT1 = 90;
private final static double EXPECTED1 = QUANTITY1 * PRICE1 * ( DISCOUNT1 / 100 );
private final static int QUANTITY2 = 4;
private final static double PRICE2 = 5;
private final static double DISCOUNT2 = 80;
private final static double EXPECTED2 = QUANTITY2 * PRICE2 * ( DISCOUNT2 / 100 );
@Test
public void testPriceCalculation(){
PriceCalculator priceCalculator = new PriceCalculator(QUANTITY1, PRICE1, DISCOUNT1);
assertEquals("price calculated for test data1",
EXPECTED1, priceCalculator.getPrice(), 0);
PriceCalculator priceCalculator2 = new PriceCalculator(QUANTITY2, PRICE2, DISCOUNT2);
assertEquals("price calculated for test data2",
EXPECTED2, priceCalculator2.getPrice(), 0);
}
}
The disadvantage of this solution: here I have two sets of test data, so duplicate static attribute QUANTITY2, PRICE2, DISCOUNT2 and EXPECTED2 are introduced, which is a violation of DRY – Don’t Repeat Yourself.
A better solution
import static org.junit.Assert.assertEquals;
import java.util.Arrays;
import java.util.Collection;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
@RunWith(Parameterized.class)
public class RunWithTwoTestCase {
private int quantity;
private double price;
private double discount;
private double expected;
private PriceCalculator priceCalculator;
public RunWithTwoTestCase(int qty, double price, double discount, double expected){
this.quantity = qty;
this.price = price;
this.discount = discount;
this.expected = expected;
}
@Parameters(name = "{index}: (Quantity {0} * Price {1}) * (Discount{2}/100) = {3}")
public static Collection<Object[]> generateData()
{
return Arrays.asList(new Object[][] {
{ 5, 10, 90, 45 },
{ 4, 5, 80, 16 } });
}
@Before
public void setUp() throws Exception {
this.priceCalculator = new PriceCalculator(this.quantity, this.price, this.discount);
}
@Test
public void testPrice(){
assertEquals("price calculated for test data", this.expected,
this.priceCalculator.getPrice(), 0);
}
}
Briefly introduction
The advantage of this solution is, the test data is in fact somehow separated from test class itself. In case you need more test data, you can simply append array in method generateData() without any duplicate static attributes.
Another benefit is, the test data injected with @Parameters are also available in JUnit result view, which is easier for tester to analyze result. Just compare the normal test case and the solution where @Parameters is used:
In the runtime, (1) the annotation “@org.junit.runners.Parameterized$Parameters(name={index}: (Quantity {0} * Price {1}) * (Discount{2}/100) = {3})” I write in method generateData is extracted by framework:
After that call allParameters method to retrieve test data written in test code. (2) In allParameters method, my prepared test data is passed to JUnit framework via reflective call:
(3) then my test case class is instantiated by reflection, the first set of test data is passed into constructor. After that the method annotated with @Before and @Test are executed sequentially. And then, @Before and @Test will be executed once again for the second set of test data. This could be observed by id displayed in debugger.
- [WCF权限控制]WCF自定义授权体系详解[实例篇]
- [ASP.NET MVC]通过对HtmlHelper扩展简化“列表控件”的绑定
- [ASP.NET MVC]为HtmlHelper添加一个RadioButtonList扩展方法
- 在ASP.NET MVC中使用“RadioButtonList”和“CheckBoxList”
- [WCF REST] 一个简单的REST服务实例
- [WCF REST] 提高性能的一个有效的手段:条件资源获取(Conditional Retrieval)
- [WCF REST] 解决资源并发修改的一个有效的手段:条件更新(Conditional Update)
- [WCF REST] 通过ASP.NET Output Caching实现声明式缓存
- [WCF REST] 通过ASP.NET Output Caching实现声明式缓存
- CentOS6.5下安装JDK
- 使用Maven插件构建SpringBoot项目,生成Docker镜像push到DockerHub上
- 开源API测试工具 Hitchhiker v0.8 - 自动化测试结果统计
- 腾讯AI-JavaAPI示例代码
- C++ 模板学习
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Shiro学习笔记(二)
- Shiro学习笔记 三(认证授权)
- Shiro学习笔记四(Shiro集成WEB)
- Shiro学习笔记五(Shiro标签,及通配符)
- Shiro学习笔记六(自定义Reaml-使用数据库设置 user roles permissions)
- Luncene学习 第一天 《入门程序》
- Luncene学习二《搜索索引》
- JavaWeb--简单分页技术
- 使用Python制作第一个爬虫程序
- 使用BeautifulSoup 爬取一个页面上的所有的超链接
- 使用PlaceHolder,测试碰见的问题
- 隐藏MySQL InnoDB Cluster / ReplicaSet实例
- MySQL8.0.21——错误日志中的组复制系统消息
- 【一】、搭建Hadoop环境----本地、伪分布式
- 在组复制中指定恢复IP地址