2

我正在检查我们应用程序的单元测试并改进/添加更多单元测试。我在单元测试/测试驱动开发方面相当(不,非常)新手,我找到了我想测试的以下方法。我被卡住了,我的问题是是否有办法重写它以使其可测试?

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;
}
4

1 回答 1

2

您的方法有 3 个职责:

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

为了启用测试,我会在 AssemblyInfo.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();

检索 os 字符串,而您的实际值驻留在此信息的使用中以确定 Os 是否为 32 位。

将事物包装在接口中并使用模拟框架的另一种方法是在此处应用函数式编程外观,以了解 Llewellyn Falco 的剥离和切片技术,并在此处应用 Arlo Belshee 的无模拟方法。因此,而不是像这样的方法:

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 表达式,该表达式应该只返回 os 和架构字符串。

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

  1. 将其作为方法的参数传递
  2. 使其成为您班级在施工时启动的领域
于 2013-08-19T11:18:47.377 回答