2

I have a mapping:

var config = new MapperConfiguration(cfg =>
{
    cfg.CreateMap<Foo, FooDto>()
        .ForMember(dest => dest.Id,
            opt => opt.MapFrom(src => src.Id))
        .ForMember(dest => dest.Name,
            opt => opt.MapFrom(src => src.Name))
        .ForMember(dest => dest.PhoneNumber,
            opt => opt.MapFrom(src => src.PhoneNumbers.Number)) //etc.
});

and I'm trying to use it in a unit test calling into some mocked up EF objects:

var ids = new List<string>()
    {
        "123";
        "456";
        "789";
    };
var data = new List<Foo>();
foreach(var id in ids)
{
    data.Add(new Foo() { Id = id });
}

this.mockContext = new Mock<entities>();
this.mockSet = new Mock<DbSet<Foo>>();
this.mockSet.As<IQueryable<Foo>>().Setup(p => p.Provider).Returns(data.Provider);
this.mockSet.As<IQueryable<Foo>>().Setup(p => p.Expression).Returns(data.Expression);
this.mockSet.As<IQueryable<Foo>>().Setup(p => p.ElementType).Returns(data.ElementType);
this.mockSet.As<IQueryable<Foo>>().Setup(p => p.GetEnumerator()).Returns(data.GetEnumerator());

When I query the entities directly:

var id = "123";
var bar = this.mockContext.Object.Foo.Where(p => p.id == id);

I get back an IQueryable() with a single result, as expected. But when I try to project my object into a DTO:

var id = "123";
var buzz = this.mockContext.Object.Foo.Where(p => p.id == id).ProjectTo<FooDto>(this.config);

The IQueryable I get back throws a Null Reference Exception if I try to access the results in any way. So for example:

buzz.ToList();
buzz.SingleOrDefault(); // This mirrors the actual call in my code since this is a GetById query.

both fail. What am I missing here?

Necoras
  • 6,743
  • 3
  • 24
  • 45

1 Answers1

4

The problem lies is that Foo uses EF navigation properties to refer to other objects. Specifically a PhoneNumber in this instance. Since the test data is created without the linked PhoneNumber object, it breaks inside of the ProjectTo method. This isn't a problem when grabbing the top level Queryable directly, but Automapper needs the objects to exist (even if they're empty) in order to complete the mapping. Changing that line to:

data.Add(new Foo() { Id = id, PhoneNumber = new PhoneNumber() });

allows the ProjectTo method to complete, albeit with null values.

Necoras
  • 6,743
  • 3
  • 24
  • 45