junit參數化測試

在前面的junit4初體驗中我就說過,junit參數化測試是一隻小怪獸,只逼編碼痛點,如今咱們這裏來整理一下。

看過我前面的那篇初體驗的就會發現一個問題,咱們的測試代碼大量的重複了。在這裏先貼出原來的那2篇代碼:java

測試源碼:數據庫

package test.junit4test;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public final class Linkin
{

	/**
	 * @建立時間: 2016年1月28日
	 * @相關參數: @param name
	 * @相關參數: @return
	 * @功能描述:格式化一個Java駝峯規則的字符串成數據庫規則。
	 */
	public static final String underscoreName(String name)
	{
		if (name == null)
		{
			return null;
		}
		if ("".equals(name))
		{
			return "";
		}
		StringBuilder result = new StringBuilder().append(name.substring(0, 1).toLowerCase());
		for (int i = 1; i < name.length() - 1; i++)
		{
			String s = name.substring(i, i + 1);
			String slc = s.toLowerCase();

			String pres = name.substring(i - 1, i);
			String preslc = pres.toLowerCase();

			if (!s.equals(slc) && pres.equals(preslc))
			{
				result.append("_").append(slc);
			}
			else
			{
				result.append(slc);
			}
		}
		return result.append(name.substring(name.length() - 1, name.length()).toLowerCase()).toString();
	}

	/**
	 * @建立時間: 2016年1月28日
	 * @相關參數: @param name Java對象名稱
	 * @相關參數: @return 格式化後的名稱
	 * @功能描述: 將Java對象名稱(每一個單詞的頭字母大寫)按照數據庫命名的習慣進行格式化
	 * <p>
	 * 格式化後的數據爲小寫字母,而且使用下劃線分割命名單詞。
	 * 若是參數name爲null,則返回null。
	 * 例如:employeeInfo 通過格式化以後變爲 employee_info
	 * </p>
	 */
	public static final String wordFormat4DB(String name)
	{
		if (name == null)
		{
			return null;
		}
		Pattern p = Pattern.compile("[A-Z]");
		Matcher m = p.matcher(name);
		StringBuffer sb = new StringBuffer();
		while (m.find())
		{
			if (m.start() != 0)
			{
				m.appendReplacement(sb, ("_" + m.group()).toLowerCase());
			}
		}
		return m.appendTail(sb).toString().toLowerCase();
	}

}

測試代碼:數組

package test.junit4test;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;

import org.junit.Before;
import org.junit.Test;

public class LinkinTest
{
	private static final String JAVANAME = "userInfo";
	private static final String DBNAME = "user_info";
	Linkin linkin = null;

	@Before
	public void setUp()
	{
		linkin = new Linkin();
	}

	@Test
	// 測試字符串正常的狀況
	public void testUnderScoreName4Normal()
	{
		String underscoreName = linkin.underscoreName(JAVANAME);
		assertEquals(DBNAME, underscoreName);
	}

	@Test
	// 測試字符串爲null的狀況
	public void testUnderScoreName4Null()
	{
		String underscoreName = linkin.underscoreName(null);
		assertNull(underscoreName);
	}

	@Test
	// 測試字符串爲空字符串的狀況
	public void testUnderScoreName4Empty()
	{
		String underscoreName = linkin.underscoreName("");
		assertEquals("", underscoreName);
	}

	@Test
	// 測試當首字母大寫時的狀況
	public void testUnderScoreName4Begin()
	{
		String underscoreName = linkin.underscoreName("UserInfo");
		assertEquals(DBNAME, underscoreName);
	}

	@Test
	// 測試當尾字母爲大寫時的狀況
	public void testUnderScoreName4End()
	{
		String underscoreName = linkin.underscoreName("userInfO");
		assertEquals(DBNAME, underscoreName);
	}

	@Test
	// 測試多個相連字母大寫時的狀況
	public void testUnderScoreName4Together()
	{
		String underscoreName = linkin.underscoreName("userINfo");
		assertEquals(DBNAME, underscoreName);
	}

}

爲了保證單元測試的嚴謹性,咱們模擬了不一樣類型的字符串來測試方法的處理能力,爲此咱們編寫大量的單元測試方法。但是這些測試方法都是大同小異:代碼結構都是相同的,不一樣的僅僅是測試數據和指望值。有沒有更好的方法將測試方法中相同app

的代碼結構提取出來,提升代碼的重用度,減小複製粘貼代碼的煩惱?在之前的 JUnit 版本上,並無好的解決方法,而如今您可使用 JUnit 提供的參數化測試方式應對這個問題。函數


參數化測試的編寫稍微有點麻煩(固然這是相對於 JUnit 中其它特性而言):
1,爲準備使用參數化測試的測試類指定特殊的運行器 org.junit.runners.Parameterized。

2,爲測試類聲明幾個變量,分別用於存放指望值和測試所用數據。單元測試

3,爲測試類聲明一個使用註解 org.junit.runners.Parameterized.Parameters 修飾的,返回值爲 java.util.Collection 的公共靜態方法,並在此方法中初始化全部須要測試的參數對。測試

4,爲測試類聲明一個帶有參數的公共構造函數,並在其中爲第二個環節中聲明的幾個變量賦值。ui

5,編寫測試方法,使用定義的變量做爲參數進行測試。this


咱們按照這個標準,從新改造一番咱們的單元測試代碼:
package test.junit4test;

import java.util.Arrays;
import java.util.Collection;

import org.junit.Assert;
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 LinkinTest
{
	private String expected;
	private String target;

	@Parameters
	public static Collection<String[]> words()
	{
		return Arrays.asList(new String[][] { { "employee_info", "employeeInfo" }, // 測試通常的處理狀況
				{ null, null }, // 測試 null 時的處理狀況
				{ "", "" }, // 測試空字符串時的處理狀況
				{ "employee_info", "EmployeeInfo" }, // 測試當首字母大寫時的狀況
				{ "employee_info_a", "employeeInfoA" }, // 測試當尾字母爲大寫時的狀況
				{ "employee_a_info", "employeeAInfo" }// 測試多個相連字母大寫時的狀況
		});
	}

	/**
	 * @建立時間: 2016年1月28日
	 * @相關參數: @param expected 指望的測試結果,對應參數集中的第一個參數
	 * @相關參數: @param target 測試數據,對應參數集中的第二個參數
	 * @構造描述: 參數化測試必須的構造函數
	 */
	public LinkinTest(String expected, String target)
	{
		this.expected = expected;
		this.target = target;
	}

	/**
	 * 測試將 Java 對象名稱到數據庫名稱的轉換
	 */
	@Test
	public void wordFormat4DB()
	{
		Assert.assertEquals(expected, Linkin.wordFormat4DB(target));
	}

}


很明顯,代碼瘦身了。在靜態方法 words 中,咱們使用二維數組來構建測試所須要的參數列表,其中每一個數組中的元素的放置順序並無什麼要求,只要和構造函數中的順序保持一致就能夠了。如今若是再增長一種測試狀況,只須要在靜態方法 words 中添加相應的數組便可,再也不須要複製粘貼出一個新的方法出來了。運行上面的測試,將會根據@Parameters註解修飾的方法返回一個Collection,而後進行相同次數的循環。編碼

如今咱們來逐步分析下parameters這隻小怪獸在junit中的運行過程,以理解這份強大的功能:

1,首先junit調用了靜態方法words,而後junit爲words這個集合中的每一個數組進行循環。

2,junit調用惟一的構造器,注意這個時候,若是該測試類存在多個構造器,junit就會拋出一個斷言錯誤。


3,junit使用由該數組參數構成的一系列參數來調用構造器,而後開始一次測試。

4,重複上面的步驟,直到都運行完Collection集合中的數組元素。



junit的parameterized類是junit衆多測試運行器的一個。測試運行器可讓你控制junit如何運行測試。咱們可使用別的運行器,也能夠自定義本身的運行器來使用,使用RunWith就能夠。下一篇咱們就來整理下junit運行器。

相關文章
相關標籤/搜索