2

I've created a method called ListOfPeople and trying to write a Unit Test for it. Currently, I am having trouble setting up the Arrange section of my Unit Test. I can't run it right now because my PeopleId and PersonGroupJobId states Cannot resolve symbol.

Question: How can I test this method successfully?

My Method:

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;
        }

Unit Test:

[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());
    }
StuartLC
  • 104,537
  • 17
  • 209
  • 285
ChaseHardin
  • 2,189
  • 7
  • 29
  • 50
  • 1
    Like @David Arno said, you have to create a new `DB.Person` and initialize the `PeopleId` and `PersonGroupJobId` on the person. Besides that, I'd think about the naming of your Method. Is `ListOfPeople` a good name? Or would something along `GetPersonWithId(...)` be better? If I read `ListOfPerson`, I'd think that its a property `IList ListOfPeople { get; set; }` – xeraphim Jul 15 '15 at 14:27
  • Why are you arranging the `PeopleId` etc of the people list with `It.IsAny()`? just give them some real numbers. In the act you already say that `.ListOfPeople()` takes any int as input – xeraphim Jul 15 '15 at 14:31
  • @xeraphim good point. Thanks for the tip on naming, I'll change that so it's more descriptive. – ChaseHardin Jul 15 '15 at 14:37

2 Answers2

3

You aren't initialising your list properly. You need:

var people = new List<DB.Person>
{
    new DB.Person
    {    
        PeopleId = It.IsAny<int>(),
        PersonGroupdJobId = It.IsAny<int>()
    }
};
David Arno
  • 42,717
  • 16
  • 86
  • 131
3

You aren't using Moq's It matchers correctly. Matchers are intended for use in Moq's Setup and Verify calls (e.g. see here for example usage)

  • In the arrange, you shouldn't use use an It.IsAny when creating fake data. All that will happen with It.IsAny<> is that the values will be assigned default(Type), i.e. zero for Ints etc, which isn't going to be useful.

var people = new List<DB.Person>
 {
   new DB.Person
   {        
       PeopleId = 1234, // Some traceable value and NOT It.IsAny<int>(),
       PersonGroupdJobId = 987,
       ...
  • In the act step, you need to invoke the method under test with values which exercise the scenario (again, not just It.IsAny<>):

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

Also, since the method being tested has at least two concerns, viz applying a filter to the repository, and then mapping out a DB entity to another POCO, you need to provide a complete set of input data so that you can prove that all input fields are mapped to output fields.

If you put all this together, your unit test will look something like:

[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());
}
Community
  • 1
  • 1
StuartLC
  • 104,537
  • 17
  • 209
  • 285
  • I've stuck a working set of code [up here](https://gist.github.com/nonnb/a2bd872fa50915635663) after making some assumptions about the types of the POCO properties. The two mocks seem to be member fields in your `Test` class, so you can remove these. – StuartLC Jul 15 '15 at 15:12