我如何开始单元测试?总共n00b的问题,想法?

时间:2009-11-05 02:56:28

标签: c# .net unit-testing

所以我开始编写一个有用的方法的类库,这些方法已经写好了多年,我将从两个代码示例开始,然后问我具体的问题:

我还想提出一个论点,即是其他一些副本的副本,“我从哪里开始单元测试问题。”

检查网络连接(不是互联网,只是网络)

    public static Boolean IsNetworkConnected()
    {
        Boolean ret = false;
        try
        {
            String HostName = System.Net.Dns.GetHostName();
            System.Net.IPHostEntry thisHost = System.Net.Dns.GetHostEntry(HostName);
            String thisIpAddr = thisHost.AddressList[0].ToString();

            ret = thisIpAddr != System.Net.IPAddress.Parse("127.0.0.1").ToString();
        }
        catch (Exception)
        {
            return false;
        }
        return ret;
    }

我的IsValiEmail方法(注意,我没有写正则表达式)

   public const String MatchEmailPattern = @"^(([\w-]+\.)+[\w-]+|([a-zA-Z]{1}|[\w-]{2,}))@"
         + @"((([0-1]?[0-9]{1,2}|25[0-5]|2[0-4][0-9])\.([0-1]?[0-9]{1,2}|25[0-5]|2[0-4][0-9])\."
         + @"([0-1]?[0-9]{1,2}|25[0-5]|2[0-4][0-9])\.([0-1]?[0-9]{1,2}|25[0-5]|2[0-4][0-9])){1}|"
         + @"([a-zA-Z]+[\w-]+\.)+[a-zA-Z]{2,4})$";


    public static bool IsValidEmail(string email)
    {
        if (email != null && email != string.Empty) 
            return Regex.IsMatch(email, MatchEmailPattern);
        else 
            return false;
    }

所以,我的问题是如何测试这些方法是否真的有效,显然我想开始单元测试更多的代码,这些代码比这些快速示例更复杂。

如果可能的话,我想避免安装其他工具/框架,但我愿意接受你的想法。

更新

应该这个新的单元测试代码(通过已发布的链接)实时?在同一个集会?一个单独的组装?

8 个答案:

答案 0 :(得分:5)

看看这本书。 The art of unit testing。维基页面有很多很棒的资源。

答案 1 :(得分:3)

NUnit可能是最适合您需求的单元测试框架。看看他们的quick start教程。

答案 2 :(得分:2)

你可以在没有框架的情况下进行单元测试 - 只需使用运行测试的“测试”按钮制作应用程序。但是,我发现使用现有框架要好得多 - 它们的设置允许您轻松添加测试,查看成功/失败,并自动运行测试。 Nunit很好,或者说真的,任何事都可以。如果你有一个随附的Visual Studio版本,MSTest就可以了。

IsValidEmail应该很容易测试:使用null,“”,有效的电子邮件和无效的电子邮件进行测试。然后戴上黑帽子,试着偷偷摸摸地进入有害垃圾:你可以让它破裂吗?但由于此功能仅对其输入进行操作,因此很容易测试。

IsNetworkConnected更难测试。您调用GetHostName和GetHostEntry,您无法控制它们返回的内容。这使得很难检查所有可能的模式。单元测试会给您带来很大的压力,要求您将逻辑与数据检索分开。这里的一个选择是传入IPHostEntry。当然,这会使你的异常陷阱变得不那么有用,并将其中的一部分推送给调用者。

您可以构建一个函数来为您调用GetHostName和GetHostEntry,然后将代理传递给应用程序中的真实代理和测试中的伪代码。在某种程度上,这种策略的成本高于其提供的价值 - 您必须自己做出判断,不要在不产生价值的工作上浪费精力。

* Mock Objects技术的追随者会注意到你不应该嘲笑GetHostName和GetHostEntry,因为你不拥有它们。如果你有一个模拟框架并希望使用它,请随意;只是不要错误地使用他们的工具来遵循他们的设计方法。

答案 3 :(得分:2)

测试IsNetworkConnected

Sean McMillan的回答是正确的,即测试IsNetworkConnected方法没有多大好处。它没有封装很多逻辑,只包含了不值得抽象的依赖。但是,让我们假装由于某种原因对该方法进行单元测试很重要。以下是我要采用的方式:

  public static Boolean IsNetworkConnected(IIPAddressProvider ipAddressProvider) 
    { 
        Boolean ret = false; 
        try 
        {
            IPAddress thisIpAddr = ipAddressProvider.GetIPAddressOFLocalHost();
            ret = thisIpAddr.ToString() != System.Net.IPAddress.Parse("127.0.0.1").ToString(); 
        } 
        catch (Exception) 
        { 
            return false; 
        } 
        return ret; 
    }   

这样做后,我会编写以下单元测试:

  • 从IIPAddressProvider的模拟中抛出异常
  • 从IIPAddressProvider
  • 的模拟返回Null IPAddress
  • 从IIPAddressProvider
  • 的模拟返回127.0.0.1
  • 从IIPAddressProvider
  • 的模拟中返回127.0.0.1以外的其他IPAddress

测试IsValidEmail

为此方法编写单元测试有一定的价值。您需要尝试正面,负面和边界测试用例。单元测试也是白盒测试的形式。从您的方法中可以清楚地看到,您需要在进行单元测试时对方法的前置条件和正则表达式进行练习。这里重要的是运用正则表达式。该方法中的代码路径不多。在我看来,你需要编写上面提到的测试用例场景。此外,在生产代码中使用它之前,应使用一些用于进行正则表达式验证的第三方工具。

应在何处找到测试代码

在我看来,它应始终位于与生产代码不同的程序集中。那是最好的选择。

答案 4 :(得分:1)

对于第一部分代码,您需要介绍Dependency Inversion,以便您可以模拟这些依赖项并控制何时返回true并返回false。

对于第二个,我会创建一些NUnit测试,每个测试都传入有效或无效的电子邮件,并验证是否返回了正确的结果。您可以通过为每个要测试的电子邮件创建一个测试或创建一个测试作为行测试(使用NUnit 2.5 +)来实现此目的。

至于测试应该在哪里......好吧,他们可以住在同一个组件或另一个组件中......目前,最佳做法似乎是将它们放在一个单独的组件中。如果您有一个名为MyProject的项目,那么您可以为您的单元测试创​​建一个名为MyProject.Tests ....的项目。另外,将集成测试放在另一个名为MyProject.Integration.Tests的程序集中是很好的。

答案 5 :(得分:1)

可以找到一些额外的单元测试框架here

答案 6 :(得分:0)

您可以从Junit开始,您可以使用模拟框架(如mockito)来模拟涉及使用框架的代码部分。但是要使用模拟框架,您需要将使用外部框架的部分代码隔离到单独的类或接口中,并使用模拟框架来模拟外部依赖项。

同样在您的代码中,您使用“==”运算符进行字符串比较。


ret = thisIpAddr != System.Net.IPAddress.Parse("127.0.0.1").ToString();

但是你应该使用“equals”方法进行字符串比较。

答案 7 :(得分:0)

与Asaph一致,NUnit是使用最广泛的框架。话虽如此,如果您不想使用其他框架,VStudio Professional确实内置了单元测试工具 我建议您将测试放在同一个解决方案中,在一个单独的项目中,这样您就不必使用组件发送测试。
你的第一个案例实际上并不是最明显的单元测试,因为你的类有一个难以复制的外部依赖:显然,如果类测试机器是连接的,结果本身将取决于机器的状态。机。换句话说,如果测试失败,您不知道是因为您的代码,还是因为某些代码无法控制。这些情况通常是通过Mocking来实现的,但如果您不熟悉单元测试,这可能不是最简单的事情!
第二种情况是一个更好的起点;基本上你必须创建有效和无效的地址,并将它们传递给你的方法,并检查结果是否应该是什么。