单元测试示例?

eig*_*yes 25 language-agnostic unit-testing

我理解测试驱动开发背后的想法,首先编写测试,代码反对测试,直到它成功.它还没有在我的工作流程中为我而来.

您能举例说明单元测试可用于前端或后端Web开发环境吗?

mfa*_*nto 70

你没有指定一种语言,所以我会尝试保持这种通用性.但这很难,因为用实际代码表达概念要容易得多.

单元测试起初可能有点令人困惑.有时,并不总是清楚如何测试某些东西,或者测试的目的是什么.

我喜欢将单元测试视为测试小块代码的一种方法.

我使用单元测试的第一个地方是验证某些方法的工作方式与我期望的所有情况一样.我刚刚为我的网站编写了一个电话号码验证方法.我接受任何输入,从123-555-1212,(123)555-1212等.我想确保我的验证方法适用于所有可能的格式.没有单元测试,我将被迫手动输入每种不同的格式,并检查表单是否正确发布.这非常乏味且容易出错.稍后,如果有人对手机验证码进行了更改,如果我们可以轻松检查以确保没有其他任何损坏,那将是很好的.(也许我们增加了对国家代码的支持).所以,这是一个简单的例子:

public class PhoneValidator
{
    public bool IsValid(string phone)
    {
          return UseSomeRegExToTestPhone(phone);
    }
}
Run Code Online (Sandbox Code Playgroud)

我可以像这样写一个单元测试:

public void TestPhoneValidator()
{
     string goodPhone = "(123) 555-1212";
     string badPhone = "555 12"

     PhoneValidator validator = new PhoneValidator();

     Assert.IsTrue(validator.IsValid(goodPhone));
     Assert.IsFalse(validator.IsValid(badPhone));
}
Run Code Online (Sandbox Code Playgroud)

这2个Assert行将验证从IsValid()返回的值分别为true和false.

在现实世界中,你可能会有很多好的和坏的电话号码的例子.我测试了大约30个电话号码.以后简单地运行此单元测试将告诉您手机验证逻辑是否已损坏.

我们还可以使用单元测试来模拟我们无法控制的事物.

单元测试应独立于任何外部资源运行.您的测试不应该依赖于存在的数据库或可用的Web服务.因此,我们模拟这些资源,因此我们可以控制它们返回的内容.例如,在我的应用程序中,我无法在注册时模拟被拒绝的信用卡.银行可能不希望我提交数以千计的不良信用卡只是为了确保我的错误处理代码是正确的.这是一些示例代码:

public class AccountServices
{
   private IBankWebService _webService = new BankWebService();

   public string RegisterUser(string username, string creditCard)
   {
        AddUserToDatabase(username);

        bool success = _webService.BillUser(creditCard);

        if (success == false)
           return "Your credit card was declined"
        else
           return "Success!"

    }
}
Run Code Online (Sandbox Code Playgroud)

这是单元测试非常混乱且不明显的地方.这种方法的测试应该怎样做?首先,如果我们检查一下,如果计费失败,则会返回相应的错误消息,这将是非常好的.事实证明,通过使用模拟,有一种方法.我们使用所谓的控制反转.现在,AccountServices()负责创建BankWebService对象.让我们让这个类的调用者提供它:

public class AccountServices
{
   public AccountServices(IBankWebService webService)
   {
       _webService = webService;
   }

   private IBankWebService _webService;

   public string RegisterUser(string username, string creditCard)
   {
        AddUserToDatabase(username);

        bool success = _webService.BillUser(creditCard);

        if (success == false)
             return "Your credit card was declined"
        else
           return "Success!"

    }
}  
Run Code Online (Sandbox Code Playgroud)

因为调用者负责创建BankWebService对象,所以我们的Unit测试可以创建一个假的:

public class FakeBankWebService : IBankWebService
{
    public bool BillUser(string creditCard)
    {
        return false; // our fake object always says billing failed
    }
}

public void TestUserIsRemoved()
{
    IBankWebService fakeBank = FakeBankWebService();

    AccountServices services = new AccountServices(fakeBank);

    string registrationResult = services.RegisterUser("test_username");

    Assert.AreEqual("Your credit card was declined", registrationResult);
}
Run Code Online (Sandbox Code Playgroud)

通过使用那个假对象,只要我们的银行的BillUser()被调用,我们的假对象将始终返回false.我们的单元测试现在验证如果对银行的调用失败,RegisterUser()将返回正确的错误消息.

假设有一天你做了一些改变,一个bug爬进来:

public string RegisterUser(string username, string creditCard)
{
    AddUserToDatabase(username);

    bool success = _webService.BillUser(creditCard);

    if (success) // IT'S BACKWARDS NOW
        return "Your credit card was declined"
    else
        return "Success!"

}
Run Code Online (Sandbox Code Playgroud)

现在,当您的结算失败时,您的RegisterUser()方法将返回"Success!".幸运的是,你有一个单元测试.该单元测试现在将失败,因为它不再返回"您的信用卡被拒绝".

以这种方式查找错误要比使用不良信用卡手动填写注册表单更简单快捷,只需检查错误消息即可.

一旦你看到不同的模拟框架,你就可以做更强大的事情.您可以验证您的假方法是否被调用,您可以验证方法被调用的次数,您可以验证调用方法的参数等.

我想一旦你理解了这两个想法,你就会理解为你的项目编写大量的单元测试.

如果你告诉我们你正在使用的语言,我们可以更好地指导你.

我希望这有帮助.如果其中一些令人困惑,我道歉.如果事情没有意义,我会清理它.

  • 这非常有帮助,我只想得到一个基本的理解,非常感谢你! (2认同)
  • 很高兴它有所帮助.单元测试一开始似乎难以理解,一旦点击就会非常容易.对我来说,更多的是学习如何编写可测试的代码.你用的是哪种语言?我们可以为您的特定语言提供更好的建议. (2认同)