2013-04-18 43 views
3

我正在通过我们的应用程序的单元测试,并改进/添加更多。我很(不,很)新手在单元测试/测试驱动开发,我发现了以下方法,我想测试。我被卡住了,我的问题是如果有一种方法来重写这个,以便它是可测试的?重写操作系统查询方法变得可测试

public static bool Is32BitOS() 
{ 
     string os = (from x in new ManagementObjectSearcher("SELECT * FROM Win32_OperatingSystem").Get().OfType<ManagementObject>() 
        select x.GetPropertyValue("Caption")).First().ToString().Trim(); 

     if (os.Equals("Microsoft Windows XP Professional")) 
     { 
      return true; 
     } 

     if (os.StartsWith("Microsoft Windows 7")) 
     { 
      string architecture = (from x in new ManagementObjectSearcher("SELECT * FROM Win32_OperatingSystem").Get().OfType<ManagementObject>() 
            select x.GetPropertyValue("OSArchitecture")).First().ToString(); 
      if (architecture == "64-bit") 
      { 
       return false; 
      } 
     } 

     return true; 
} 
+2

您可以随时换行'ManagementObjectSearcher'在瘦界面,这将自动让你的依赖清晰可见,并可以轻松地用于其他实现,例如测试...只是一个想法(我在电话中,所以它很简短;)) –

+2

如果您使用的是.NET 4.0,请查看'Environment.Is64BitOperatingSystem()'方法http://msdn.microsoft.com/ en-us/library/system.environment.is64bitoperatingsystem%28VS.100%29.aspx – bniwredyc

+0

检查[此问题](http://stackoverflow.com/q/336633/706456) – oleksii

回答

2

你的方法有3个职责:

  1. 管理对象搜索创建
  2. 操作系统和架构检索
  3. 操作系统验证

为了使测试我的程序集信息添加.cs与此类似的行:

[assembly: InternalsVisibleTo("Your.Test.Project")] 

这样受保护的方法对测试项目可见,但对客户端不可用。 然后使该操作系统验证分开后,我已经重写你的方法:

//Acceptance test this method 
public static bool Is32BitOS() 
{ 
    var managementObjects = new ManagementObjectSearcher("SELECT * FROM Win32_OperatingSystem").Get().OfType<ManagementObject>(); 

    string os = (from x in managementObjects select x.GetPropertyValue("Caption")).First().ToString().Trim(); 
    string architecture = (from x in managementObjects select x.GetPropertyValue("OSArchitecture")).First().ToString(); 

    return Is32BitOS(os, architecture); 
} 

//Unit test this method 
internal static bool Is32BitOS(string os, string architecture) 
{ 
    if (os.Equals("Microsoft Windows XP Professional")) 
    { 
     return true; 
    } 

    if (os.StartsWith("Microsoft Windows 7")) 
    { 
     string architecture = archRetriever(); 
     if (architecture == "64-bit") 
     { 
      return false; 
     } 
    } 
    return true; 
} 

现在我们已经分开的担忧我会说,你的单元测试应该只验证Is32BitOs行为,同时验收测试应当验证端到端堆栈。 事实上,你有单元测试的小值

(from x in new ManagementObjectSearcher("SELECT * FROM Win32_OperatingSystem").Get().OfType<ManagementObject>() 
select x.GetPropertyValue("Caption")).First().ToString().Trim(); 

,而你真正的价值在于这些信息的使用情况,以确定如果操作系统是32位检索OS字符串。

另一种在接口中封装并使用嘲讽框架的方法是应用函数式编程看看here for Llewellyn Falco's peel and slice techniquehere Arlo Belshee's no mocks approach。因此,而不是一个方法,如:

public static bool Is32BitOS(IRetrieveOsAndArchitecture roa) 
{ 
    string os = roa.GetOs();     
    string architecture = roa.GetArchitecure(); 

    return Is32BitOS(os, architecture); 
} 

您可以使用类似:

public static bool Is32BitOS(Func<ManagementObjectSearcher, string> osRetriever, 
          Func<ManagementObjectSearcher, string> archRetriever, 
          ManagementObjectSearcher searcher) 
{ 
    string os = osRetriever(searcher);    
    string architecture = archRetriever(searcher); 

    return Is32BitOS(os, architecture); 
} 

其客户端的方法是:

public static bool Is32BitOS() 
{ 
    var searcher = new ManagementObjectSearcher("SELECT * FROM Win32_OperatingSystem"); 

    return Is32Bit((s)=>{ (from x in s.Get().OfType<ManagementObject>() select x.GetPropertyValue("Caption")).First().ToString().Trim()}, 
        (s)=>{ (from x in s.Get().OfType<ManagementObject>() select x.GetPropertyValue("OSArchitecture")).First().ToString();}, 
        searcher); 
} 

注意,在测试的接口和功能的情况下,你没有使用真正的ManagementObjectSearcher外部依赖;在mockist方法中,您将在函数式编程中使用模拟对象,您将传递不同的lambda表达式,该lambda表达式应只返回os和体系结构字符串。

这个方法还有一个责任,就是创建ManagementObjectSearcher;要解决这种依赖关系,您可以:

  1. 将它作为方法的参数
  2. 使其在构建时initilized类的领域