标签:
本文主要介绍Visual Studio(2012+)单元测试框架的一些技巧:
namespace BlogDemo.UTDemo.Tricks
{
public class StaticConstructorExample
{
static StaticConstructorExample()
{
//step1:read data from web service
//step2:save data into database
}
public int DoSomething()
{
return 0;
}
}
}
上面的类有一个静态构造函数,里面做两件事情:
以上两件事情都是对外界环境的严重依赖
我们需要测试的方法是DoSomething,需要测试这个类,就需要实例化StaticConstructorExample这个类,实例化这个类之前,其静态构造函数将会被自动执行:这个点就是问题。
解决办法依然是Shim,通过ms.test的Shim可以模拟一个类的静态构造函数,从而改变静态构造函数的行为,消除外部依赖。
[TestClass]
public class StaticConstructorExampleTests
{
[TestMethod]
public void DoSomethingTest()
{
using (ShimsContext.Create())
{
var isStaticConstructorExecuted = false;
ShimStaticConstructorExample.StaticConstructor = () =>
{
//step1:mock web service
//step2:mock database
isStaticConstructorExecuted = true;
};
var example = new StaticConstructorExample();
var data = example.DoSomething();
Assert.AreEqual(0, data);
Assert.IsTrue(isStaticConstructorExecuted);
}
}
}
上面的代码是通过ShimClassName.StaticConstructor来实现对静态构造函数进行模拟的。
基础代码,在DemoClass中进行调用
public interface IGoodActionHandler
{
void Action();
}
public interface IBadActionHandler
{
void Action();
}
public class GoodHandler : IGoodActionHandler
{
public void Action()
{
throw new NotImplementedException();
}
}
public class BadHandler : IBadActionHandler
{
public void Action()
{
throw new NotImplementedException();
}
}
要被测试的类:
public class DemoClass
{
IGoodActionHandler goodHandler;
IBadActionHandler badHandler;
public DemoClass()
{
this.goodHandler = new GoodHandler();
this.badHandler = new BadHandler();
}
public void DoSomething(int type)
{
if (type == 1)
{
DoSomethingGood();
}
else
{
DoSomethingBad();
}
}
private void DoSomethingGood()
{
this.goodHandler.Action();
}
private void DoSomethingBad()
{
this.badHandler.Action();
}
}
要测试上面的DoSomething方法,上面DoSomethingGood和DoSomethingBad都依赖自接口,在测试的时候都可以进行mock(stub)。在侧测DoSomething方法是只需要验证当Type为1时执行了goodHandler的action,否则执行badHandler的Action。
这也是单元测试的一个关键点:关注单元。这里不关注goodhandler 和badhandler的内部逻辑(这两个handler的内部逻辑可以单独测试,属于另外的单元),这里只关注是否按照逻辑路由到了正确的handler。
[TestClass]
public class DemoClassTests
{
[TestMethod]
public void DoSomething_DoSomethingGood_Tests()
{
var goodHandlerExecuted = false;
StubIGoodActionHandler goodHandler = new StubIGoodActionHandler()
{
Action = () =>
{
goodHandlerExecuted = true;//如果执行了goodhandler则置为true
}
};
var badHandlerExecuted = false;
StubIBadActionHandler badHandler = new StubIBadActionHandler()
{
Action = () =>
{
badHandlerExecuted = true;//如果执行了badhandler则置为true
}
};
var demoClass=new DemoClass();
demoClass.BadHandler=badHandler;//注入badhandler
demoClass.GoodHandler=goodHandler;//注入goodhandler
demoClass.DoSomething(1);
Assert.IsTrue(goodHandlerExecuted);//执行了goodhandler
Assert.IsFalse(badHandlerExecuted);//没有执行badhandler
}
}
上面使用了两个技术
上面的标志位的方法Shim技术照样使用,静态构造函数的模拟就是通过Shim后在构造函数内部修改标识位来验证构造函数被执行的。接下来介绍的测试执行次数也是通过shim后修改标识位来实现的
public class DemoClass
{
private LoopHandler handler;
public DemoClass()
{
handler = new LoopHandler();
}
public void DoSomething(int times)
{
for (var i = 0; i < times; i++)
{
handler.Do();
}
}
}
public class LoopHandler
{
public void Do() { }
}
现在要验证DoSomething是否执行了times次Do方法。
[TestMethod]
public void DoSomething_RunTimes_Test()
{
using(ShimsContext.Create())
{
var times = 0;
ShimLoopHandler.AllInstances.Do = (@this) =>
{
times++;//每进入一次加一次
};
var givenTimes = 100;
new DemoClass().DoSomething(givenTimes);
Assert.AreEqual(times, givenTimes);
}
}
思想和上面Stub是一样,在Shim模拟的方法内部进行计数器相加。
这里有一点需要注意一下,因为int的++不是线程安全的,如果把DemoClass的循环修改成多个线程并行执行的话测试代码需要做相应的调整。,对times++进行lock。
public void DoSomething(int times)
{
Parallel.For(0, times, (item) =>//并行执行
{
handler.Do();
});
}
[TestMethod]
public void DoSomething_RunTimes_Test()
{
using(ShimsContext.Create())
{
var times = 0;
ShimLoopHandler.AllInstances.Do = (@this) =>
{
lock (this)//lock线程安全
{
times++;//每进入一次加一次
}
};
var givenTimes = 100;
new DemoClass().DoSomething(givenTimes);
Assert.AreEqual(times, givenTimes);
}
}
上面的代码当Times不是特别大的时候一般不加lock也是可以的,不是特别大的时候一般不会产生线程安全问题。但是当times比较大的时候不加lock就会出问题。
当times是100000时去掉lock。我运行就出现了问题:
测试就是为了严谨,如果有上面并行的问题,测试的时候还是加上lock比较好。
Unit Test Via Visual Studio-Part5
标签:
原文地址:http://www.cnblogs.com/kmpp/p/Unit_Test_Tricks.html