【问题标题】:Arranging Unit Test using Moq使用 Moq 安排单元测试
【发布时间】:2015-10-04 15:26:57
【问题描述】:

我创建了一个名为ListOfPeople 的方法并尝试为其编写单元测试。目前,我无法设置 单元测试Arrange 部分。我现在无法运行它,因为我的 PeopleIdPersonGroupJobId 状态为 Cannot resolve symbol

问题: 我怎样才能成功地测试这个方法?

我的方法:

public IEnumerable<Person> ListOfPeople(int personId, int? jobId)
        {
            var people = _unitOfWork.GetRepository<DB.Person>().GetAll()
              .Where(p => p.PeopleGroups.Any(m => m.PeopleId == personId 
                              && m.PersonGroupdJobId == jobId));

            if (!people.Any())
                return new List<Person>();

            var personData = people.Select(p => new Person
            {
                Id = p.PersonId,
                Name = p.PersonName,
                WorkTypeId = p.WorkTypeId,
                PrimaryLanguage = p.PrimaryLanguage,
                PeopleGroups = p.PeopleGroups.ToList()
                  .Select(pp => new PeopleGroup
                  {
                      Id = pp.ProjectPartyId,
                      PeopleId = pp.PeopleId,
                      JobId = pp.PersonGroupJobId ?? 0,
                      AddressId = pp.AddressId
                  })
            }).ToList();

            return personData;
        }

单元测试:

[TestMethod]
    public void ListOfPeople_peopleExist_returnsList()
    {
        // Arrange
        var people = new List<DB.Person>
        {    
            PeopleId = It.IsAny<int>(),
            PersonGroupdJobId = It.IsAny<int>()
        }; 

        _uowMock
            .Setup(mock => mock.GetRepository<DB.Person>().GetAll())
            .Returns(people.AsQueryable());

        // Act
        var result = _repository.ListOfPeople(It.IsAny<int>(), It.IsAny<int>());

        // Assert
        Assert.IsNotNull(result);
        Assert.AreEqual(2, result.Count());

        _unitOfWork.Verify(mock => mock.Commit(), Times.Never());
        _unitOfWork.Verify(mock => mock.GetRepository<DB.Person>().GetAll(), Times.Once());
    }

【问题讨论】:

  • 就像@David Arno 所说,您必须创建一个新的DB.Person 并在此人上初始化PeopleIdPersonGroupJobId。除此之外,我会考虑你的方法的命名。 ListOfPeople 是个好名字吗?或者GetPersonWithId(...) 旁边的东西会更好吗?如果我阅读ListOfPerson,我会认为它是一个属性IList&lt;Person&gt; ListOfPeople { get; set; }
  • 你为什么要把人列表的PeopleId等和It.IsAny&lt;int&gt;()排列在一起?给他们一些真实的数字。在行为中,您已经说过 .ListOfPeople() 将任何 int 作为输入
  • @xeraphim 好点。感谢您提供有关命名的提示,我将对其进行更改,使其更具描述性。

标签: c# asp.net unit-testing moq


【解决方案1】:

您没有正确使用 Moq's It 匹配器。匹配器旨在用于 Moq 的 SetupVerify 调用(例如 see here 的用法)

  • 在安排中,您不应在创建虚假数据时使用It.IsAnyIt.IsAny&lt;&gt; 会发生的所有事情就是将值分配给default(Type),即对于 Ints 等为零,这将没有用处。

var people = new List<DB.Person>
 {
   new DB.Person
   {        
       PeopleId = 1234, // Some traceable value and NOT It.IsAny<int>(),
       PersonGroupdJobId = 987,
       ...
  • 在执行步骤中,您需要使用执行场景的值调用被测方法(同样,不仅仅是It.IsAny&lt;&gt;):

var result = _repository.ListOfPeople(1234, 567); // Filters matching your test scenario

另外,由于被测试的方法至少有两个关注点,即对存储库应用过滤器,然后将数据库实体映射到另一个 POCO,因此您需要提供一套完整的输入数据,以便您可以证明所有输入字段都映射到输出字段。

如果您将所有这些放在一起,您的单元测试将如下所示:

[Test]
public void ListOfPeople_peopleExist_returnsList()
{
    // Arrange : Generate fake data
    var people = new List<DB.Person>
    {    
        new DB.Person
        {
            PersonId = 123,
            PersonName = "Bob",
            PrimaryLanguage = "French",
            WorkTypeId = 987,
            PeopleGroups = new []
            {
                new DB.PeopleGroup
                {
                    AddressId = 123,
                    PersonGroupJobId = 999,
                    PeopleId = 123, // Match the parent ID
                    ProjectPartyId = 3
                }
            }
        }
    };

    // Your _unitOfWork and _repository mocks seem to be class private fields
    var _unitOfWork = new Mock<IUnitOfWork>();

    _unitOfWork
        .Setup(mock => mock.GetRepository<DB.Person>().GetAll())
        .Returns(people.AsQueryable());

    var _repository = new MyRepo(_unitOfWork.Object);

    // Act
    var result = _repository.ListOfPeople(123, 999);

    // Assert
    Assert.IsNotNull(result);
    Assert.AreEqual(1, result.Count(r => r.Name == "Bob" 
                                         && r.Id == 123 
                                         && r.PeopleGroups.First().Id == 3));
  //... etc - ensure all the fields are mapped 

    _unitOfWork.Verify(mock => mock.Commit(), Times.Never());
    _unitOfWork.Verify(mock => mock.GetRepository<DB.Person>().GetAll(), 
                       Times.Once());
}

【讨论】:

  • 在对 POCO 属性的类型进行了一些假设之后,我坚持了一组工作代码 up here。这两个模拟似乎是您的 Test 类中的成员字段,因此您可以删除这些。
【解决方案2】:

您没有正确初始化列表。你需要:

var people = new List<DB.Person>
{
    new DB.Person
    {    
        PeopleId = It.IsAny<int>(),
        PersonGroupdJobId = It.IsAny<int>()
    }
};

【讨论】:

  • 我同意我没有正确初始化这个,但这仍然给我同样的错误。还有其他想法吗?
  • @CodeChaser,我需要查看DB.Person 的来源以提供进一步帮助
猜你喜欢
  • 2011-12-24
  • 1970-01-01
  • 1970-01-01
  • 2015-07-13
  • 2015-09-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多