性能测量工具类——TimeMeasureUtil & TimeMeasureProxy

TimeMeasureUtil:做单次时间测量。

1、为了能确保 startTime 和 endTime 都正确设置,因而采用实例对象来实现。每次测量是都能判断对象是否处在正确状态。

2、该类为工具类,即使测试时产生许多对象实例也对软件无任何影响。

public class TimeMeasureUtil {
	private long startTime = 0;
	private long endTime = 0;
	
	private TimeMeasureUtil(){
		
	}
	
	public static TimeMeasureUtil newInstance(){
		return new TimeMeasureUtil();
	}
	
	public void start(){
		startTime = System.currentTimeMillis();
	}
	
	public void end(){
		endTime = System.currentTimeMillis();
	}
	
	public long measure(){
		
		// Invalid: Before y
		if( startTime == 0 ){
			throw new IllegalStateException( "Must call metod start() first, when call method measure()." );
		}
		if( endTime == 0 ){
			throw new IllegalStateException( "Must call metod end() first, when call method measure()." );
		}
		if( startTime > endTime ){
			throw new IllegalStateException( "Must call metod start() first, when call method end()." );
		}
		
		return endTime - startTime;
	}

}

使用示例:

	@Test
	public void testMeasure_ok() {
		TimeMeasureUtil timeUtil = TimeMeasureUtil.newInstance();
		timeUtil.start();
		
		// 下面这段代码用实际待测方法代替
		try {
			Thread.sleep( 1000 );
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		timeUtil.end();
		
		assertEquals( 1000, timeUtil.measure() );
	}


由于单次测量可能的偏差太大,没有统计意义,如下类测量平均时间!
TimeMeasureProxy:

1、默认运行20次得平均

2、给定运行次数的平均

缺陷:

1、由于是用反射实现,参数是通过 Object[ ] 来传递。有原始类型(如:byte,int,char...)参数的方法不能测试!只能用 TimeMeasureUtil 来实现测试。 

2、如果第一次执行方法后改变了某属性,而该属性改变后又会影响下一次方法的执行(可能会有不同的时间),这样的方法不能测试。可能的改进方式:先“克隆” count 个该对象,然后用这样相同属性的对象来执行方法(每个对象执行一次方法)。因为这样要求,被测试类提供“克隆”方法,“因测试而影响逻辑”不可取,所以没有实现。

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class TimeMeasureProxy {
	
	// default measure count
	private int count = 20;
	
	private TimeMeasureProxy(){
		
	}
	
	private TimeMeasureProxy( int count ){
		this.count = count;
	}
	
	public static TimeMeasureProxy newInstance(){
		return new TimeMeasureProxy();
	}
	
	public static TimeMeasureProxy newInstance( int count ){
		return new TimeMeasureProxy( count );
	}
	
	public long avgTime( Object owner, String methodName, Object[] args ){
		
		// valid parameters.
		if( owner == null ){
			throw new IllegalStateException("owner can't be null.");
		}
		if( methodName == null ){
			throw new IllegalStateException("methodName can't be null.");
		}
		
		Class<?> ownerClass = owner.getClass();
		Class<?>[] argsClass = null;
		if( args != null ){
			argsClass = new Class[ args.length ];
			for( int i=0 ; i<args.length ; i++ ){
				argsClass[i] = args[i].getClass();
			}
		}

		Method method;
		try {
			method = ownerClass.getMethod( methodName, argsClass );
		} catch (SecurityException e) {
			throw new RuntimeException( e );
			
		} catch (NoSuchMethodException e) {
			throw new RuntimeException( e );
		}
		
		return totalTime( owner, method, args)/count;
	}
	
	long totalTime( Object owner, Method method, Object[] args ){
		long totalTime = 0;
		
		try {
			for( int i=0; i<count ; i++ ){
				TimeMeasureUtil timeUtil = TimeMeasureUtil.newInstance();
				timeUtil.start();
				method.invoke( owner, args );
				timeUtil.end();
				totalTime += timeUtil.measure();
			}
		} catch (IllegalArgumentException e) {
			throw new RuntimeException( e );
		} catch (IllegalAccessException e) {
			throw new RuntimeException( e );
		} catch (InvocationTargetException e) {
			throw new RuntimeException( e );
		}
		
		return totalTime;
	}

}

使用示例:

1、待测试的类

class ForMeasureAvgTime{
	
	public void justForTest(){
		try {
			Thread.sleep( 335 );
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public void justForTestWithParams( Integer age, String name ){
		try {
			Thread.sleep( 558 );
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

2、通过TimeMeasureProxy 来测试

	@Test
	//测量无参数方法&默认次数(20)
	public void testAvgTime_defaultCount() {
		ForMeasureAvgTime forMeasure = new ForMeasureAvgTime();
		
		TimeMeasureProxy proxy = TimeMeasureProxy.newInstance();
		long avgTime = proxy.avgTime( forMeasure, "justForTest", null );
		
		System.out.println( "avgTime=" + avgTime );
		assertTrue( (avgTime - 335) < 5 || (335 - avgTime) < 5);
	}
	
	@Test
	//测量有参数方法&给定次数(10)
	public void testAvgTime_giveCount() {
		ForMeasureAvgTime forMeasure = new ForMeasureAvgTime();
		
		TimeMeasureProxy proxy = TimeMeasureProxy.newInstance( 10 );
		long avgTime = proxy.avgTime( forMeasure, "justForTestWithParams", new Object[]{24, "GongQiang"} );
		
		System.out.println( "avgTime=" + avgTime );
		assertTrue( (avgTime - 558) < 5 || (558 - avgTime) < 5);
	}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值