51Testing软件测试论坛

标题: 第一个UT测试-增加注释 [打印本页]

作者: marcus1877    时间: 2013-7-23 16:40
标题: 第一个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?
作者: goal1860    时间: 2013-7-25 07:16
public还是internal取决于外部调用的需要,而不是UT的需要,一切internal/private的方法变量都是不能直接测试的,但是假如它们没有最终被public的方法调用到就是无用代码,应当删除。
总的来讲没有开发经验去写UT是比较困难的。尤其是web服务层的ut要mock的东西比较多。
作者: marcus1877    时间: 2013-7-30 09:53
回复 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必须的,搞不好就推不动。必须在可测试与以前常规方法之前取舍一个。
作者: goal1860    时间: 2013-7-31 09:29
我看的很混乱,StartFiles假如是internal的,那怎么能用Manager.StartFiles调用呢?这和Manager是不是stub貌似没有关系。
Manager对象我猜测是由依赖注入模式控制的,所以才需要做stub,假如是这样的话DataShare就不能用常规构造器来产生,通常应该有相应的服务返回一个DataShare实例。
从你的描述来看系统设计的耦合度很高,造成UT困难,因为牵扯的依赖太多了。一般要开发改设计是不太可能的。如果可能的话你应当建议由系统的设计和编码人员来做UT,最好是做TDD。
作者: marcus1877    时间: 2013-7-31 10:01
本帖最后由 marcus1877 于 2013-7-31 10:10 编辑

回复 4# goal1860
非常感谢,StartFiles是Manager类的一个方法,声明为internal,所以可以Manager实例调用。由于UT代码里要调用StartFiles,自然要把Manager做成Stub,才能调用假的StartFiles。这段 在1楼上有写出来。

因为都没做过UT,所以确实头疼...
作者: marcus1877    时间: 2013-7-31 15:29
找到一篇E文,与我第二个问题相似,个人认为开发环境是VS+C#时都可以这么考虑。

http://programmers.stackexchange ... s-inside-same-class
作者: marcus1877    时间: 2013-7-31 15:38
找到一个E文参考,正好是C#的,应该可以按他们的方法修改
http://programmers.stackexchange ... s-inside-same-class
作者: marcus1877    时间: 2013-7-31 15:40
最佳答案目前只能选择4楼。
作者: marcus1877    时间: 2013-7-31 15:42
目前只能选择4楼作为答案
作者: marcus1877    时间: 2013-7-31 16:40
目前最佳答案只能给4楼了。
作者: marcus1877    时间: 2013-7-31 16:44
目前最佳答案只能给4楼了。




欢迎光临 51Testing软件测试论坛 (http://bbs.51testing.com/) Powered by Discuz! X3.2