• junit4初体验


    OK,现在我们正式开始junit4系列的整理。前面的junit38作为4的补充知道就好了,实际编码中我们以4为主。这里先来一把junit的初体验,同时也让我们来一步一步的了解下TDD的好处。

    ORM大家肯定熟悉的不能再熟悉了,大Java面向对象编码,但是数据库存的是表结构,所以我们不可避免的就要来做ORM映射。其中关键的一步就是将Java对象映射成数据库中的表,将一个Java对象的属性映射成数据库一个表的一个字段。

    在这里我们就写一个工具类,将Java对象名称按照数据库命名的习惯来进行格式化。假如我们现在还没有任何的测试,一般的TDD中都是测试先行,先写个测试方法,因为没有任何的测试源代码,所以这个时候测试方法中要fail出去一个异常。然后人工去实现测试然后接着测试。在这里我们就不用先写那个失败的测试方法了,我们这里直接编码一个方法来实现刚才那个功能。

    代码如下:

    public String underscoreName(String name)
    	{
    		StringBuilder result = new StringBuilder();
    		result.append(name.substring(0, 1).toLowerCase());
    		for (int i = 1; i < name.length(); i++)
    		{
    			String s = name.substring(i, i + 1);
    			String slc = s.toLowerCase();
    			if (!s.equals(slc))
    			{
    				result.append("_").append(slc);
    			}
    			else
    			{
    				result.append(s);
    			}
    		}
    		return result.toString();
    	}
    OK,现在方法写好了,那我们开始写测试。

    @Test
    	public void testUnderScoreName4Normal()
    	{
    		Linkin linkin = new Linkin();
    		String underscoreName = linkin.underscoreName("userInfo");
    		assertEquals("user_info", underscoreName);
    	}


    OK,写的这个测试用例通过了,那是不是就万事大吉了呢?NO,NO,NO,现在就宣布代码通过了单元测试还为时过早。我们应该记住:单元测试代码不是用来证明我是对的,而是为了证明我没有错。 因此单元测试的范围要全面,比如对边界值、正常值、错误值得测试;对代码可能出现的问题要全面预测,而这也正是需求分析、详细设计环节中要考虑的。显然, 我们的测试才刚刚开始,继续补充一些对特殊情况的测试。

    OK,现在我们来写相关测试:

    package test.junit4test;
    
    import static org.junit.Assert.assertEquals;
    import static org.junit.Assert.assertNull;
    
    import org.junit.Test;
    
    public class LinkinTest
    {
    
    	@Test
    	// 测试字符串正常的情况
    	public void testUnderScoreName4Normal()
    	{
    		Linkin linkin = new Linkin();
    		String underscoreName = linkin.underscoreName("userInfo");
    		assertEquals("user_info", underscoreName);
    	}
    
    	@Test
    	// 测试字符串为null的情况
    	public void testUnderScoreName4Null()
    	{
    		Linkin linkin = new Linkin();
    		String underscoreName = linkin.underscoreName(null);
    		assertNull(underscoreName);
    	}
    
    	@Test
    	// 测试字符串为空字符串的情况
    	public void testUnderScoreName4Empty()
    	{
    		Linkin linkin = new Linkin();
    		String underscoreName = linkin.underscoreName("");
    		assertEquals("", underscoreName);
    	}
    
    	@Test
    	// 测试当首字母大写时的情况
    	public void testUnderScoreName4Begin()
    	{
    		Linkin linkin = new Linkin();
    		String underscoreName = linkin.underscoreName("UserInfo");
    		assertEquals("user_info", underscoreName);
    	}
    
    	@Test
    	// 测试当尾字母为大写时的情况
    	public void testUnderScoreName4End()
    	{
    		Linkin linkin = new Linkin();
    		String underscoreName = linkin.underscoreName("userInfO");
    		assertEquals("user_info", underscoreName);
    	}
    
    	@Test
    	// 测试多个相连字母大写时的情况
    	public void testUnderScoreName4Together()
    	{
    		Linkin linkin = new Linkin();
    		String underscoreName = linkin.underscoreName("userINfo");
    		assertEquals("user_info", underscoreName);
    	}
    
    }
    
    测试代码写好以后,运行结果如下:



    忽忽,蛋疼的情况出现了,2个错误,2个失败,好吧,说明我们的代码问题还是挺多的呢。开始改吧。

    public 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();
    	}
    OK,现在测试全部通过了,现在是不是万事大吉了呢?NO,NO,NO,代码写的太糙了,只是为了我们测试通过,现在我们修改自己的测试代码,让代码更加漂亮点。

    修改后的测试代码如下:

    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);
    	}
    
    }
    
    原来的被测试源码如下:

    package test.junit4test;
    
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    
    public class Linkin
    {
    
    	/**
    	 * @创建时间: 2016年1月28日
    	 * @相关参数: @param name
    	 * @相关参数: @return
    	 * @功能描述:格式化一个Java驼峰规则的字符串成数据库规则。
    	 */
    	public 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 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();
    	}
    
    }
    
    上面的这段代码有2个方法,第一个方法我是从spring-jdbc-template中复制出来,但是很遗憾并没有严格的通过我自己写的单元测试。下面的代码我自己写的,也实现了类似的功能。如果感兴趣,可以自行补上测试。


    总结:

    1,JUnit 将测试失败的情况分为两种:failure 和 error。Failure 一般由单元测试使用的断言方法判断失败引起,它表示在测试点发现了问题;而 error 则是由代码异常引起,这是测试目的之外的发现,它可能产生于测试代码本身的错误(测试代码也

    是代码,同样无法保证完全没有缺陷),也可能是被测试代码中的 一个隐藏的bug。

    2,再次强调,单元测试只能保证你的代码没有错,但是不能保证你的代码是对的。异常测试是一个很重要的很重要的一部分,一定不能忽略这部分测试。

    3,及时的重构源代码,有单元测试在不怕重构没法测试,重构对于自己的源码的结构和设计都会是越来越好,比如什么高内聚,低耦合,比如什么单一职责,比如取消重复等等。

    4,及时的维护测试代码,测试代码也是代码,也需要我们维护,这样很方便我们向后兼容迭代代码。比如说上面的测试类,我们写了大量的重复,每次都是传入1个字符串然后去比较我们的预期和实际,在后面的系列中我会讲到一只小怪兽,Parameterized这个后面再说。


    junit4初体验就先体验到这里,下一篇我会重点整理下junit4的几个常用的注解和使用。

  • 相关阅读:
    src和href属性的区别
    cookie, sessionStorage和localStorage的区别
    C# base64 转 byte[]
    C# 中字符串string和字节数组byte[]的转换
    C#获取当前路径的七种方法 【转载】
    C# 读取大文件 (可以读取3GB大小的txt文件)
    伪装文件到图片工具
    nmap命令扫描存活主机
    .deb文件如何安装,Ubuntu下deb安装方法图文详解
    kali修改更新源及更新
  • 原文地址:https://www.cnblogs.com/LinkinPark/p/5232891.html
Copyright © 2020-2023  润新知