zoukankan      html  css  js  c++  java
  • 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.




    要获取更多Jerry的原创文章,请关注公众号"汪子熙":

  • 相关阅读:
    Linux常用命令大全
    Shell常用命令整理
    登录织梦后台提示用户名不存在的解决方法介绍
    dedecms系统后台登陆提示用户名密码不存在
    dede被注入后台提示用户名不存在解决方法
    织梦dedecmsV5.7联动类型无法显示的处理方法
    漏洞安全防范
    Sublime 安装、插件CoolFormat
    如何查看sublime安装了哪些插件
    本地如何使用phpstudy环境搭建多站点
  • 原文地址:https://www.cnblogs.com/sap-jerry/p/13607031.html
Copyright © 2011-2022 走看看