做完基本的web环境配置和Spring配置,紧接就要填设计entity模型并编写它们在数据层和业务层了吧?先不着急,有很多Web通用的东西的需要准备,比如说,最基本东东,单元测试。好的,今天就让我的Web Application 建立起单元测试模块吧。关于这一点,很快我们会想到两个熟悉的框架,JUnit 和TestNG。也不知道众高手们喜欢哪一个,笔者选择的是JUnit。

比起3要灵活好多,用注解的方式规避了一些诸如方法名必须test开头的硬性要求,而且我们本身就是需要去更加熟悉注解的好处的。那么,果断搜罗Junit4的资料吧。Junit 的官网服务器down中,不过还是可以从github下截最新的jar 包junit-4.11.jar,当然如果需要看源码,可以解junit4.11.zip 这一包找到所有你需要的jars。

      首先建立另外的源包testsrc,无论是什么IDE,都可以设置不部署/发布该包中的build,很明显,这样设置的原因在于test代码不需要在product中存在。那么上文所说的jar 也没有必要放在WEB-INF/lib下,只需要设置在IDE或说开发环境的classpath下(笔者是eclipse添加user lib 'SpringJunit4' )。当然,如果需要版本控制系统track测试源码包,就需要将jar包放到合适的位置了。

                                           

java软件功能测试报告模版 java模块测试_测试

接着,在com.xxxx.webmodel.util建个工具class,例如一定会用到的String 加密或者是文件内容摘要的工具类,这里笔者命名它为DataHash. 代码如下


1. package
2.  
3. import
4. import
5.  
6. public class
7. private
8. private String d4tAlgorithm="SHA1"; 
9. public
10. return
11.     } 
12.  
13. public void
14. this.msgDigest = msgDigest; 
15.     } 
16.      
17. public String encryptData(byte[] content){ 
18. null; 
19. if(msgDigest == null) 
20. try
21.                 msgDigest = MessageDigest.getInstance(d4tAlgorithm); 
22. byte[] resultBytes =msgDigest.digest(content); 
23. new
24. catch
25.                 e.printStackTrace(); 
26.             } 
27. return
28.     } 
29.      
30. public
31. byte[] bytes = string.getBytes(); 
32. return this.encryptData(bytes); 
33.     } 
34.      
35. public boolean
36. if(typedString!=null && correctString !=null){ 
37. this.encryptData(typedString); 
38. return
39. else return false; 
40.     } 
41.  
42. }

       在eclipse 中 右键点击该类文件,New-> JUnit Test Case , 弹出了生成TestCase 的属性对话框,有Jutni3 与4 的单选框,这里选择4,将Source folder Browse到testsrc,将package 名中的项目名和模块名间加个test。将setUpBeforeClass, tearDownAfterClass setUp tearDown 四个方法前的checkbox勾上。

java软件功能测试报告模版 java模块测试_开发工具_02

        点Next后, 将要测试的方法前checkbox勾上,

java软件功能测试报告模版 java模块测试_Test_03

 

后就生成了testsrc下com.xxxxx.webmodel.test.util包下的DataHashTest.java. 其中setUpBeforeClass()由@BeforeClass 注解,tearDownAfterClass由@AfterClass注解以及setUp 与tearDown分别被@BeforeClass与@AfterClass注解。 都是什么意思呢?一试便知。在每个方法中写入方法标识的控制台输出语句,顺便加上构造方法一并测试。代码如下

      

1. package
2.  
3. import static
4.  
5. import
6. import
7. import
8. import
9. import
10. import
11.  
12. import
13.  
14. public class
15.  
16. @BeforeClass
17. public static void init() throws
18. "BeforeClass"); 
19.     } 
20.  
21. @AfterClass
22. public static void dispose() throws
23. "AfterClass"); 
24.     } 
25.      
26. public
27. "Constructor"); 
28.     } 
29.  
30. @Before
31. public void startTest() throws
32. "Before"); 
33.     } 
34.  
35. @After
36. public void endTest() throws
37. "After"); 
38.     } 
39.  
40. @Test
41. public void
42. "Test1"); 
43. "Not yet implemented"); 
44.     } 
45.  
46. @Test
47. public void
48. "Test2"); 
49. "Not yet implemented"); 
50.     } 
51.  
52. }

        在Eclipse的编辑器中右键选择Run as或者Debug as, 次级对话框中选择JUnit Test, 控制台会输出

BeforeClass

Constructor

Before

Test1

After

Constructor

Before

Test2

After

AfterClass

       很明显setUpBeforeClass会在整个测试周期的开始被执行,tearDownAfterClass是整个测试周期结束时执行, 每个一方法的测试周期都会生成一个新的测试类对象,然后按以下顺序执行:setUp 测试方法,tearDown.由于JUnit4中方法名不需固定,用注解即可,所以这四个方法的名字是可以自定义的,笔者这里换为了init,dispose, startTest endTest.

       之后,就真正测试一下吧,在本测试类里加入成员变量 testedObj, 类型是DataHash, 并完成那那个方法,代码如下

 


1. private
2. @Test
3. public void
4. "Test string"; 
5.         String testedOut = testedObj.encryptData(testedStr); 
6.         Assert.assertFalse(testedStr.equals(testedOut)); 
7.          
8. "Test1"); 
9.     } 
10.  
11. @Test
12. public void
13. "Test string"; 
14.         String testedOut = testedObj.encryptData(testedStr); 
15.         Assert.assertTrue(testedObj.passWords(testedStr, testedOut)); 
16. "Test2"); 
17.     }

        初始化testedObj的语句可以放在构造方法里,或是setUp中,当然也可以做成静态变量,在startUpBeforeClass方法中初始化使得整个测试周期只用一个DataHash的对象。同样的方法运行这个写好的测试类,结果如下:

                                                

java软件功能测试报告模版 java模块测试_java软件功能测试报告模版_04

 

        发现第二个方法测出了问题,去Debug发现,在上面DataHash的String encryptData(byte[] content)方法中,if(msgDigest == null) 写错了地方,应该是作为判断是否初始化msgDigest的,结果写在了try块的外面。

       更改后,再运行,测试通过。

     

        这里有两个测试方法,如果测试方法多了,会出现一个问题,就是有些测试方法还未写完,或说有些方法不需要在整个测试周期中被测试时,却想要集中测试一个或多个方法该怎么办? @Ignore 注解在这里就发挥了作用。在不需要被测试的方法上面标注@Ignore 使其在测试运行时被忽略。

       上述的测试方案只能够运用在单独写那么一个类,可是我们的WebApplication通常是有上下文环境的。例如一个Service类对象中,需要有一个数据访问层的对象,建立这个对象需要连数据库等等的配置,即使都在@BeforeClass注解的方法中做到了,有时也还是需要一些事务类的方法做切面的, OK, @Before 和@After是可以做到,不过要在每个类中去重写这些代码,工程量未免有些太大了?

       说来说去,就是缺少Spring架在Web中的环境嘛,Spring早为我们做好了,那就是org.springframewor.test包的作用。不必啰嗦,直接上代码吧:

 


        这里关键就要是类头上的那三个注解了吧。 @RunWith是junit的注解,用以将环境代入,具体的环境的类应该是由 它(上下文环境)方自定义的类,上面用的是Spring 中的一个runner类,这样Spring的上下文环境,就被代到了测试中。@ContextConfiguration将我们写的注解配置引入,另外在测试运行时需要到一些Spring的中的bean,那就由@TestExecutionListeners来完成,这里面配置了 提供依赖注入的Listener和刷新bean配置(一些测试方法会改变bean原来的配置)的 脏位Listener,在测试DAO时还会用到解析事务配置的Listener.

1. package
2.  
3. import
4.  
5. import
6. import
7. import
8. import
9. import
10. import
11. import
12. import
13. import
14.  
15. import
16. import
17.  
18. @RunWith(SpringJUnit4Cla***unner.class) 
19. @ContextConfiguration(classes={ApplicationContext.class}) 
20. @TestExecutionListeners( { DependencyInjectionTestExecutionListener.class, DirtiesContextTestExecutionListener.class
21. public class
22. @BeforeClass
23. public static void init() throws
24. new WebConfiguration().onStartup(null); 
25. //      Properties defaultParameters= WebConfiguration.getSysParams();
26. //      defaultParameters.put("jdbc.driver", "com.mysql.jdbc.Driver");
27. //      defaultParameters.put("jdbc.url", "jdbc:mysql://localhost/webmodel");
28. //      defaultParameters.put("jdbc.username", "root");
29. //      defaultParameters.put("jdbc.password", "root");
30. //      defaultParameters.put("hibernate.dialect","org.hibernate.dialect.MySQLDialect");
31.     } 
32.      
33. private
34.      
35. public
36. return
37.     } 
38. @Resource
39. public void
40. this.appCtx = appCtx; 
41.     } 
42.  
43. @Test
44. public final void
45. "accountEntity"); 
46. "accountEntity"); 
47.         Assert.assertNotSame(objAccountA,objAccountB); 
48. "hibernatePersistencePin"); 
49. "hibernatePersistencePin"); 
50.         Assert.assertSame(persitenceA, persitenceB); 
51.     } 
52.  
53. }

       这个类中,还需要要加载一些sysParam上的配置,本来我是在@BeforeClass中完成了,上面代码段中注释掉的代码,但有时还是会与已经写好的properties文件弄混,就是在想“本来properties已经配置好了,怎么在这里没有?” 毕竟测试环境不是Web环境,为了逼真地将Web环境代入,笔者加了些代码在WebConfiguration的onStartUp中,主要目的就是发现加载不到sysParams.properties时,去以非web的方式(开发环境的相对文件路径)找到sysParam.properties 文件并加载。 然后在@BeforeClass的方法中去调用onStartUp方法,没有servletContext,传个null进去就好。

      上面的代码的测试用例,笔者是针对Spring的单例与多例模式做个简单的测试,读者们可以做下这个测试。accountEntity是标注了@Scope(“prototype”)的bean。hibernatePersistencePin是未标注的Scope即单例的bean。将spring的applicationContext注入到该测试类中的appCtx, 以使上述两种bean可以从中得到。

      关于单元测试的内容,就分享到这里。


转载于:https://blog.51cto.com/palmtale/1085144