`
掌心童话
  • 浏览: 14755 次
  • 性别: Icon_minigender_1
  • 来自: 大连
社区版块
存档分类
最新评论

Java Web Application 自架构 二 单元测试模块

阅读更多

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


       JUnit 4比起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包放到合适的位置了。

 

图1

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

 

package com.xxxxx.webmodel.util;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class DataHash {
	private MessageDigest msgDigest;
	private String d4tAlgorithm="SH1";
	public MessageDigest getMsgDigest() {
		return msgDigest;
	}

	public void setMsgDigest(MessageDigest msgDigest) {
		this.msgDigest = msgDigest;
	}
	
	public String encryptData(byte[] content){
		String result =null;
		if(msgDigest == null)
			try {
				msgDigest = MessageDigest.getInstance(d4tAlgorithm);
				byte[] resultBytes =msgDigest.digest(content);
				result= new String(resultBytes);
			} catch (NoSuchAlgorithmException e) {
				e.printStackTrace();
			}
		return result;
	}
	
	public String encryptData(String string){
		byte[] bytes = string.getBytes();
		return this.encryptData(bytes);
	}
	
	public boolean passWords(String typedString,String correctString){
		if(typedString!=null && correctString !=null){
		String ecStr = this.encryptData(typedString);
		return ecStr.equals(correctString);}
		else return false;
	}

}  
 

 

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

图2

 

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

 

图3

 

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

 

package com.xxxxx.webmodel.test.util;

import static org.junit.Assert.fail;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

import com.gxino.webmodel.util.DataHash;

public class DataHashTest {

	@BeforeClass
	public static void init() throws Exception {
		System.out.println("BeforeClass");
	}

	@AfterClass
	public static void dispose() throws Exception {
		System.out.println("AfterClass");
	}
	
	public DataHashTest(){
		System.out.println("Constructor");
	}

	@Before
	public void startTest() throws Exception {
		System.out.println("Before");
	}

	@After
	public void endTest() throws Exception {
		System.out.println("After");
	}

	@Test
	public void testEncryptDataString() {
		System.out.println("Test1");
		fail("Not yet implemented");
	}

	@Test
	public void testPassWords() {
		System.out.println("Test2");
		fail("Not yet implemented");
	}

}
 

 

      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, 并完成那那个方法,代码如下

 

private DataHash testedObj;
	@Test
	public void testEncryptDataString() {
		String testedStr = "Test string";
		String testedOut = testedObj.encryptData(testedStr);
		Assert.assertFalse(testedStr.equals(testedOut));
		
		System.out.println("Test1");
	}

	@Test
	public void testPassWords() {
		String testedStr = "Test string";
		String testedOut = testedObj.encryptData(testedStr);
		Assert.assertTrue(testedObj.passWords(testedStr, testedOut));
		System.out.println("Test2");
	}
  

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

 

图4

 

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

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


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


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


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

 

package com.xxxxxx.webmodel.test.entity;

import javax.annotation.Resource;

import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
import org.springframework.test.context.support.DirtiesContextTestExecutionListener;

import com.gxino.webmodel.util.ApplicationContext;
import com.gxino.webmodel.util.WebConfiguration;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes={ApplicationContext.class})
@TestExecutionListeners( { DependencyInjectionTestExecutionListener.class, DirtiesContextTestExecutionListener.class })
public class ComponetSingletonTest {
	@BeforeClass
	public static void init() throws Exception{
		new WebConfiguration().onStartup(null);
//		Properties defaultParameters= WebConfiguration.getSysParams();
//		defaultParameters.put("jdbc.driver", "com.mysql.jdbc.Driver");
//		defaultParameters.put("jdbc.url", "jdbc:mysql://localhost/webmodel");
//		defaultParameters.put("jdbc.username", "root");
//		defaultParameters.put("jdbc.password", "root");
//		defaultParameters.put("hibernate.dialect","org.hibernate.dialect.MySQLDialect");
	}
	
	private org.springframework.context.ApplicationContext appCtx;
	
	public org.springframework.context.ApplicationContext getAppCtx() {
		return appCtx;
	}
	@Resource
	public void setAppCtx(org.springframework.context.ApplicationContext appCtx) {
		this.appCtx = appCtx;
	}

	@Test
	public final void testWhetherAccountEntityPrototype() {
		Object objAccountA=appCtx.getBean("accountEntity");
		Object objAccountB=appCtx.getBean("accountEntity");
		Assert.assertNotSame(objAccountA,objAccountB);
		Object persitenceA=appCtx.getBean("hibernatePersistencePin");
		Object persitenceB=appCtx.getBean("hibernatePersistencePin");
		Assert.assertSame(persitenceA, persitenceB);
	}

}
 

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


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


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


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

分享到:
评论

相关推荐

    MVC架构在JSP+JavaBean开发模式中的应用 Application of MVC Framework in JSP+JavaBean Model

    在介绍Model-View-Controller(MVC)架构原理的基础上,分析了用Java开发Web系统的两种模式,提出将MVC架构思想融入JSP+JavaBean开发模式的方案。该方案能够发挥JSP+JavaBean代码编写容易、重复利用性高的优点,同时有效...

    微型JavaWeb框架pippo.zip

    它是一个开源(Apache许可证)微型Java Web框架,拥有最少的依赖,以及快速的学习曲线。 该项目的目标是创建一个微型的Web框架在Java中这应该是易于使用和破解。 其概念是不是新的 (灵感来自于 Sinatra, Express JS...

    UI自动化测试框架,支持APP、Web、HTML5三端, 基于SpringBoot框架, 支持消息通知、失败截屏+源代码+文档说

    ## 前端自动化测试框架包含如下模块: APP 自动化测试框架、HTML5 网页自动化测试框架、Web网页自动化测试框架。 * APP 自动化测试框架主要用于移动端APP自动化测试项目,目标程序运行在移动设备上。 * HTML5 网页...

    java 面试题 总结

    Hashtable继承自Dictionary类,而HashMap是Java1.2引进的Map interface的一个实现。 最大的不同是,Hashtable的方法是Synchronize的,而HashMap不是,在多个线程访问Hashtable时,不需要自己为它的方法实现同步,而...

    OSGI原理最佳实践(包含源代码)

    是一本适合新接触OSGI开发学习的一本很好的书,本书介绍了Equinox, Spring-DM和Felix这三个常用的OSGi容器的使用、开发、以及WebApplication的开发部署;介绍了OSGi的规范和Core Framework和Layer。包含书中的用例源...

    JAVA毕业设计之基于springboot的的学生干部管理系统(springboot+mysql)完整源码.zip

    基于Spring Boot的学生干部管理系统是一个用于管理学生干部信息、活动记录和通讯录的Web应用程序。该系统采用了Java作为后端编程语言,使用Spring Boot框架进行快速开发,同时结合MySQL数据库进行数据存储。整个系统...

    基于Java+SpringBoot+vue实现家具网上商城系统源码含文档ppt.zip

    本springboot+nodejs+vue+Elementui+mysql+maven项目, 采用idea开发,支持eclipse 基于web的B/S架构设计完成感兴趣的朋友可以下载看看哦 管理员账号:abo 密码:abo 运行SpringbootSchemaApplication.java 即可打开...

    asp.net知识库

    ASP.NET 2.0使用Web Part创建应用程序之二(共二) 体验 .net2.0 的优雅(2) -- ASP.net 主题和皮肤 NET2.0系列介绍(一).NET 2.0 中Web 应用程序主题的切换 ASP.NET 2.0 中Web 应用程序主题的切换 2.0正式版中...

    超级有影响力霸气的Java面试题大全文档

    Hashtable继承自Dictionary类,而HashMap是Java1.2引进的Map interface的一个实现。 最大的不同是,Hashtable的方法是Synchronize的,而HashMap不是,在多个线程访问Hashtable时,不需要自己为它的方法实现同步,而...

    应用级产品开发平台APDPlat.zip

    APDPlat提供了应用容器、多模块架构、代码生成、安装程序、认证授权、备份恢复、数据字典、web service、系统监控、操作审计、统计图、报表、机器绑定、防止破解、数据安全、内置搜索、数据转换、maven支持、WEB...

    企业级IT运维宝典之WebLogic实战

    l Web模块:HTML网页、servlet、JSP网页、有关的Java类、标准的J2EE Web配置文件、Weblogic有关的配置文件如weblogic.xml,以及其他文件如XML文件、图像文件等; l EJB模块:包含session bean、entity bean、message...

    FLEX企业应用开发实战.part1

    第4章 Flex on Java企业应用架构 第5章 BlazeDS框架详解 第6章 Flex+BlazeDS应用开发实例 第7章 将范例应用改进为真正的企业应用 第8章 Flex打印 第9章 Flex企业应用性能优化 第10章 Flex企业应用开发的其他技术 ...

    kkk-op:项目Demo

    项目组成根项目:root组件支持:support用户服务:user促销服务:sales服务架构Domain模块核心业务逻辑的集中地,包含有状态的Entity、领域服务Domain Service、以及Infrastructure模块的接口类。纯POJO模块,不依赖...

    在线考试系统文献综述

    本系统使用的是JSP技术,JSP基于Java Servlet以及整个Java体系的Web开发技术。JSP被认为是最有发展前途的动态网站技术,是未来开发动态网站的主流技术,与其它技术相比有一定的优势,如JSP页面可重用跨平台的组件...

    阿里云java短信验证码源码-guns-separation:枪炮分离

    模块化架构设计,层次清晰,业务层推荐写到单独模块,方便升级。 前后端分离架构,分离开发,分离部署,前后端互不影响。 前端技术采用vue + antdv + axios。 后端采用spring boot开源可靠。 基于spring security...

    java8源码-springboot-dubbo:初始化springboot工程的基础

    java8 源码 在这个开源的时代,贡献一点点源代码,也许一名有点点追求的程序员必经的一个阶段, 本项目主要是想帮助那些初创电商项目,做一些基础的架构演示, 只需要设计好数据库,生成mapper层代码后,做少量的...

    JAVA核心知识点整理(有效)

    25 JAVA8 与元数据.................................................................................................................................25 2.4. 垃圾回收与算法 .................................

    spring-dubbo-hdsx-x2:JAVA脚手架集成dubbo 、springboot 、seata、swagger、nacos、soul等等

    架构图整体的功能如下图:技术项目结构模块名称端口admin-web【前端】管理后台HTTP 8080user-application用户 HTTP 服务HTTP 18082product-application商品 HTTP 服务HTTP 18081order-application订单 HTTP 服务...

    scratch-microservices

    本项目演示了微服务在java-spring架构中的实现。 不同版本的复杂性和功能都在增加。 该应用程序由 2 个模块组成: 使用的主要应用程序 一种服务(迎宾服务)。 要从一个版本的代码切换到另一个版本,必须使用...

    中标麒麟服务器操作系统介绍.pdf

    基于web方式的备份 和恢复的配置管理,并能够对备份结果进行短信、邮件 通知 核心参数调整工具 提供图形化核心参数调整工具,提供对Xen和KVM的支 持,包括全虚拟化和半虚拟化,提供图形虚拟化管理工具 Java支持 JAVA...

Global site tag (gtag.js) - Google Analytics