【问题标题】:Moq, unit test using xUnit framework and testing a function returning an objectMoq,使用 xUnit 框架进行单元测试并测试返回对象的函数
【发布时间】:2017-07-10 13:00:33
【问题描述】:

我有一个仓库

public class StudentsPersonalDetailsRepository : IStudentPersonalDetailsRepository
{
    private readonly StudentManagementSystemEntities _studentsDbContext;
    private readonly ILogger _logger;
    public StudentsPersonalDetailsRepository(StudentManagementSystemEntities context, ILogger<IStudentPersonalDetailsRepository> logger)
    {
        _studentsDbContext = context;
        _logger = logger;
    }
    public IQueryable<StudentPersonalDetails> StudentPersonalDetails => _studentsDbContext.StudentPersonalDetails;
    ......
}

在我的服务层,我有一个服务

public class StudentsPersonalDetailsService:IStudentPersonalDetailsService
{
    private readonly IStudentPersonalDetailsRepository _repository;
    private readonly ILogger _logger;
    public StudentsPersonalDetailsService(IStudentPersonalDetailsRepository studentPersonalDetailsRepository,ILogger<StudentsPersonalDetailsService> logger)
    {
        _repository = studentPersonalDetailsRepository;
        _logger = logger;
    }
    ......
    ......
    public StudentModelResponse GetStudentById(int id)
    {
        Domain.Entities.StudentPersonalDetails obj = _repository.StudentPersonalDetails.
                                                    Where(i => i.RollNo == id)
                                                    .Select(i=>new Domain.Entities.StudentPersonalDetails {
                                                        RollNo=i.RollNo,
                                                        FirstName=i.FirstName,
                                                        LastName=i.LastName,
                                                        MailId=i.MailId,
                                                        MiddleName=i.MiddleName,
                                                        DateOfBirth=i.DateOfBirth,
                                                        GenderOfPerson=i.GenderOfPerson
                                                    }).FirstOrDefault();
        StudentModel ob = StudentModel.Translator(obj);
        return new StudentModelResponse { StudentModel=ob};
    }
}

我的测试代码是

namespace StudentUnitTests
{
     public class StudentServiceShould
     {
         [Theory]
         [InlineData(1)]
         public void AbleToRetrieveStudentById(int n)
         {
             var mock = new Mock<IStudentPersonalDetailsRepository>();
             var logger = new Mock<ILogger<StudentsPersonalDetailsService>> ();
             var ob = new StudentsPersonalDetailsService(mock.Object, logger.Object);
         }
     }
}

我需要为 GetStudentById() 编写一个单元测试并检查函数返回的值。

请帮助我如何模拟服务层。

【问题讨论】:

  • 先尝试一下,如果遇到问题,请提供minimal reproducible example,以便重现问题。
  • 我已经尝试过问题中编辑的那段代码。我是 Mocking 的新手,因此面临设置模拟的问题。请帮帮我。

标签: unit-testing asp.net-core-mvc moq xunit.net


【解决方案1】:

在上面我们有两件事发生在StudentsPersonalDetailsService.GetStudentById()

  1. 从存储库中检索学生信息。
  2. 根据从存储库检索到的数据创建学生模型

注意:从存储库中读取时看起来有些奇怪。如果存储库中的项目是 StudentPersonalDetails 为什么要创建新实例

我们可以像这样存根检索学生数据

 public class StudentServiceShould
 {
     [Theory]
     [InlineData(1)]
     public void AbleToRetrieveStudentById(int n)
     {
        var students = new []{
          // new Domain.Entities.StudentPersonalDetails for student role 1,
          // new Domain.Entities.StudentPersonalDetails for student role 2,
          // new Domain.Entities.StudentPersonalDetails for student role 3
        };         


         var mock = new Mock<IStudentPersonalDetailsRepository>();
         mock.SetupGet(mk => mk.StudentPersonalDetails).Returns(students.AsQueryable());
         var logger = new Mock<ILogger<StudentsPersonalDetailsService>> ();
         var ob = new StudentsPersonalDetailsService(mock.Object, logger.Object);
     }
 }

创建StudentModel 对象被封装在Translator 中,但由于它是“StudentModel”上的静态方法,我们无法模拟它,必须一次性测试读取和转换。

【讨论】:

  • 我听不懂。如果我有 1000 条记录,是否需要将所有数据输入到 var students 列表中?请解释一下我们为什么要使用 mock.Setup 以及如何设置 Returns。
  • 在您看来,单元测试的目标是什么?在上面的代码中,我们正在测试如果我们将一个 Id 号传递给StudentsPersonalDetailsService.GetStudentById(),代码将从存储库中读取相应的记录并返回从存储库返回的数据创建的StudentModelResponse。这就是我们正在测试的全部内容。模拟存储库允许我们这样做,而无需使用真实的存储库。我们只需要模拟能够返回几个不同的记录来表明这个StudentsPersonalDetailsService.GetStudentById() 工作正常
  • 好的,我明白了。谢谢你说得很清楚。如果我真的从数据库中检索它,那么它将成为集成测试。此外,我们正在隔离服务层,我们只是在测试它的行为。这真的很清楚。非常感谢!
猜你喜欢
  • 1970-01-01
  • 2018-03-29
  • 1970-01-01
  • 2012-10-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-20
相关资源
最近更新 更多