第一个UT测试-增加注释
本帖最后由 marcus1877 于 2013-7-30 09:28 编辑公司开始准备上UT测试,但是测试与开发都没经验。我与另一个developer engineer结对写UT,他进入公司前接触过,但是他的经验有限,无法从我的角度考虑UT,也不知道怎么指导我。
我的知识水平也就把【.NET单元测试艺术】(Roy Osherove)这本书看了一遍,所以这次有很多疑问,想问问资深的UT人员。
先写一个基础问题,如何写下面代码的UT
开发工具、环境:VS2012 ultimate,c#,Win8,Windows Store APP
源码类类似:
Class DataShare:IDataShare
{
bool Disposed; //这里是private的field,而且没有对应的property
Manager Manager=null;//这里是private的field,而且没有对应的property
public pubMethod1(IEnumerable<StorageFile> files) //IEnumerable是系统的,StorageFile也是系统内置
{
if (Disposed)
{
Logger.log("error","");
throw new objectException();
}
if (files !=null && files.count()>0)
{
flag=true;
Manager.StartFiles(files);
}else
{
flag=false;
}
return flag;
}
.........其他代码略.....
} //Class 结束
Class Manager
{
internal async void StartFiles(IEnumerable<StorageFile> files)
{
................
}
}
我的第一个问题是:
这里Manager是一个private field,无法设置,如果要做真正的UT,我个人认为必须把它变成internal的(或增加对应internal的属性),同时要把它的interface都抽取出来,这样我才能自己做一个stub对象,完成UT??
第二个问题是 :
StartFiles被开发人员定义为一个internal的method,那要为了做DataShare的UT,就必须把它改成Public的??这样extract interface后我的stub对象就会有startFiles方法了。
如果开发人员不把它抽取接口,那我就写不出完整的stub类了,因为不包含这个StartFiles方法!!!!!
如果要改public,那么开发人员用什么原则确保哪些method该改成public,哪些可以保持internal? public还是internal取决于外部调用的需要,而不是UT的需要,一切internal/private的方法变量都是不能直接测试的,但是假如它们没有最终被public的方法调用到就是无用代码,应当删除。
总的来讲没有开发经验去写UT是比较困难的。尤其是web服务层的ut要mock的东西比较多。 回复 2# goal1860
感谢答复,等了很久。这里我列出来的还是一个简单的情况。按照UT理论,上面Manager必须是一个stub类,可是如果StartFiles是internal的,Stub类就不能含有StartFiles方法了,那就无法UT了。
更详细复杂一些的情况是Public方法里调用很多Private方法,而Private方法又使用了很多依赖项,要想做UT,就必须全部隔离出来,那么随情况可能就会有很多隔离项。比如
Public SendCommond(IControlCommand oCommand)
{
Packet packt=null;
switch(oCmmand.Type)
{
case ControlCommandType.connecting
packet=CreateConnectingPacket(oCommand)
break;
case ControlCommandType.connecting
packet=new CommondPacket(oCommand);
beginReceive();
break;
default:
packet=new CommonPacket(oCommand);
break;
}
if (packet !=null)
{
PacketQueueManager.SendQueue(packet);
return true;
}else
{
return false;
}
}
PacketQueueManager PacketQueueManager=null;
packet CreateConnectingPacket(IControlCommand ocommand)
{ .............
}
beginReceive ()
{...................
}
为了做UT,我是不是就得把这些private方法想办法隔离出去??如果是普通项目,也许用VS的Fakes框架的shim方法就能规避,可是Windows Store APP中是无法使用Fakes框架及任何隔离工具的,比如
Rihino,Typemocker。各位高手怎么看呢?
难道是开发人员把这些方法写成virtual的,然后我的test类继承?这种方式是书里提到的一种方式。
说实话,开发人员是否愿意做这些改变我还真比较担心,因为这些可能就是要实施UT必须的,搞不好就推不动。必须在可测试与以前常规方法之前取舍一个。 我看的很混乱,StartFiles假如是internal的,那怎么能用Manager.StartFiles调用呢?这和Manager是不是stub貌似没有关系。
Manager对象我猜测是由依赖注入模式控制的,所以才需要做stub,假如是这样的话DataShare就不能用常规构造器来产生,通常应该有相应的服务返回一个DataShare实例。
从你的描述来看系统设计的耦合度很高,造成UT困难,因为牵扯的依赖太多了。一般要开发改设计是不太可能的。如果可能的话你应当建议由系统的设计和编码人员来做UT,最好是做TDD。 本帖最后由 marcus1877 于 2013-7-31 10:10 编辑
回复 4# goal1860
非常感谢,StartFiles是Manager类的一个方法,声明为internal,所以可以Manager实例调用。由于UT代码里要调用StartFiles,自然要把Manager做成Stub,才能调用假的StartFiles。这段 在1楼上有写出来。
因为都没做过UT,所以确实头疼... 找到一篇E文,与我第二个问题相似,个人认为开发环境是VS+C#时都可以这么考虑。
http://programmers.stackexchange.com/questions/188609/best-way-to-unit-test-methods-that-call-other-methods-inside-same-class 找到一个E文参考,正好是C#的,应该可以按他们的方法修改
http://programmers.stackexchange.com/questions/188609/best-way-to-unit-test-methods-that-call-other-methods-inside-same-class 最佳答案目前只能选择4楼。 目前只能选择4楼作为答案 目前最佳答案只能给4楼了。 目前最佳答案只能给4楼了。
页:
[1]