单元测试,带你快速入门

发表于:2018-7-03 16:59

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:农码一生    来源:博客园

    一个简单的测试写好了。由于我们使用的vs2017 它出了一个新的功能“Live Unit Testing”,我们可以启用它进行实时的测试。也就是我们编辑单元测试,然后保存的时候,它会自动生成自动测试,最后得出结果。
   
  
  我们看到了验证通过的绿色√。
  注意到测试代码中的参数和结果都写死了。如果我们要对多种情况进行测试,岂不是需要写多个单元测试方法或者进行多次方法执行和断言。这也太麻烦了。在XUnit框架中为我们提供了Theory特性。使用如下:
  例:
[Theory]
[InlineData(2, 3, 5)]
[InlineData(2, 4, 6)]
[InlineData(2, 1, 3)] //对应测试方法的形参
public void Add_Ok_Two(int nb1, int nb2, int result)
{
    Arithmetic arithmetic = new Arithmetic();
    var sum = arithmetic.Add(nb1, nb2);
    Assert.True(sum == result);
}

  测试了正确的情况,我们也需要测试错误的情况。达到更好的覆盖率。

      
  例:
    
       [Theory]
[InlineData(2, 3, 0)]
[InlineData(2, 4, 0)]
[InlineData(2, 1, 0)] 
public void Add_No(int nb1, int nb2, int result)
{
    Arithmetic arithmetic = new Arithmetic();
    var sum = arithmetic.Add(nb1, nb2);
    Assert.False(sum == result);
}

  有时候我们需要确定异常
  例:
   
   public int Divide(int nb1, int nb2)
{
    if (nb2==0)
    {
        throw new Exception("除数不能为零");
    }
    return nb1 / nb2;
}
[Fact]      
public void Divide_Err()
{
    Arithmetic arithmetic = new Arithmetic(); 
    Assert.Throws<Exception>(() => { arithmetic.Divide(4, 0); });//断言 验证异常
}
 
   以上为简单的单元测试。接下来,我们讨论更实际更真实的。
  我们一般的项目都离不开数据库操作,下面就来实践下对EF使用的测试:
  使用nuget安装 EntityFramework 5.0.0
  例:
    
    public class StudentRepositories
{
    //...
    public void Add(Student model)
    {
        db.Set<Student>().Add(model);
        db.SaveChanges();
    }
}
[Fact]
public void Add_Ok()
{
    StudentRepositories r = new StudentRepositories();
    Student student = new Student()
    {
        Id = 1,
        Name = "张三"
    };
    r.Add(student);

    var model = r.Students.Where(t => t.Name == "张三").FirstOrDefault();
    Assert.True(model != null);           
}
     
  我们会发现,每测试一次都会产生对应的垃圾数据,为了避免对测试的无干扰性。我们需要对每次测试后清除垃圾数据。  我们可以看到我们操作的是EF连接的实际库。(注意:要改成专用的测试库)
   
     //注意:测试类要继承IDisposable接口
  public void Dispose()
  {
  StudentRepositories r = new StudentRepositories();
  var models = r.Students.ToList();
  foreach (var item in models)
  {
  r.Delete(item.Id);
  }
  }

   这样每执行一个测试方法就会对应执行一次Dispose,可用来清除垃圾数据。
  我们知道对数据库的操作是比较耗时的,而单元测试的要求是尽可能的减少测试方法的执行时间。因为单元测试执行的比较频繁。基于前面已经对数据库的实际操作已经测试过了,所以我们在后续的上层操作使用Stub(存根)来模拟,而不再对数据库进行实际操作。
  例:
  我们定义一个接口IStudentRepositories 并在StudentRepositories 继承。
    
    public interface IStudentRepositories
 {
     void Add(Student model);
 }
 public class StudentRepositories: IStudentRepositories
 {
    //省略。。。 (还是原来的实现)
 }   
public class StudentService
{
    IStudentRepositories studentRepositories;
    public StudentService(IStudentRepositories studentRepositories)
    {
        this.studentRepositories = studentRepositories;
    }
    public bool Create(Student student)
    {
        studentRepositories.Add(student);

        return true;
    }
}

  新建一个类,用来测试。这个Create会使用仓储操作数据库。这里不希望实际操作数据库,以达到快速测试执行。
   
    [Fact]
public void Create_Ok()
{
    IStudentRepositories studentRepositories = new StubStudentRepositories();
    StudentService service = new StudentService(studentRepositories);
    var isCreateOk = service.Create(null);
    Assert.True(isCreateOk);
}

public class StubStudentRepositories : IStudentRepositories
{
    public void Add(Student model)
    {
    }
}

  图解:
  每次做类似的操作都要手动建议StubStudentRepositories存根,着实麻烦。好在Mock框架(Moq)可以自动帮我们完成这个步骤。
  例: 
    
    [Fact]
public void Create_Mock_Ok()
{
    var studentRepositories = new Mock<IStudentRepositories>();
    var notiy = new Mock<Notiy>();
    StudentService service = new StudentService(studentRepositories.Object);
    var isCreateOk = service.Create(null);
    Assert.True(isCreateOk);
}

上文内容不用于商业目的,如涉及知识产权问题,请权利人联系博为峰小编(021-64471599-8017),我们将立即处理。
32/3<123>
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号