Unit Testing your AutoMapper mappings

Valéry Raulet
All About Software Testing
4 min readFeb 7, 2023

--

Photo by israel palacio on Unsplash

AutoMapper is a great .NET library for object-to-object mapping. It transparently maps object properties unless you provide specific transformation instructions.

However, we can sometimes forget about it and run into issues because our code is not working. Too many times, I have been guilty of not testing my mappings and then spending countless hours trying to figure out what is wrong with my code…

So, if like me, you use AutoMapper, you should enforce testing your mappings, and you will end up with more free time ;-)

Project Setup

Ensure you have AutoMapper installed (same version as in the application’s code):

Install-Package AutoMapper

In this article, I created a C# NUnit test project. To use AutoMapper, you need an instance of IMapper which can be done through its configuration. Here, “TestingAutomappings” is the name of the assembly containing automappings:

[TestFixture]
public class MappingTests
{
IMapper _mapper;
MapperConfiguration _config;

[SetUp]
public void Setup()
{
_config = new MapperConfiguration(cfg => cfg.AddMaps(new[] {
"TestingAutomappings"
}));

_mapper = _config.CreateMapper();
}
}

Validation Test

The first test you should have is the configuration test. Indeed, AutoMapper has a validation method which is useful to make sure your mappings are correct:

[Test]
public void ConfigurationTest()
{
_config.AssertConfigurationIsValid();

Assert.Pass();
}

If your project already has many mappings and you are just starting with Unit Testing, this test may fail with tens of errors. In that case, comment it out and try to solve some of the issues in small chunks until they are all resolved. It will identify issues such as:

  • Duplicate mappings: The mapping between 2 classes is provided in multiple locations so AutoMapper does not know which one is the correct one (it will anyway use the last one encountered);
  • Missing mapping for a field: AutoMapper implicitly automaps fields in the 2 objects if they have the same name. If it cannot find a field to map to, you either need to explicitly tell AutoMapper how to map or you must clearly state you are ignoring the field.

Simple AutoMapping Test

Now, let’s assume you have the following code:

public class Source
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}

public class Destination
{
public int Id { get; set; }
public string Name { get; set; }
public string Help { get; set; }
}

public class SourceToDestinationMapping: Profile
{
public SourceToDestinationMapping()
{
CreateMap<Source, Destination>()
.ForMember(d => d.Help, opt => opt.MapFrom(s => s.Description))
.ReverseMap();
}
}

If you want to test this code, you need to check that Source can map to Destination, and if needed, the reverse as well:

[Test]
public void SourceToDestinationTest()
{
Source source = new()
{
Id = 1,
Name = "Test",
Description = "My description"
};

var destination = _mapper.Map<Destination>(source);

Assert.IsNotNull(destination);
Assert.That(destination.Id, Is.EqualTo(source.Id));
Assert.That(destination.Name, Is.EqualTo(source.Name));
Assert.That(destination.Help, Is.EqualTo(source.Description));
}

[Test]
public void DestinationToSourceTest()
{
Destination destination = new()
{
Id = 1,
Name = "Test",
Help = "My description"
};

var source = _mapper.Map<Source>(destination);

Assert.IsNotNull(source);
Assert.That(source.Id, Is.EqualTo(destination.Id));
Assert.That(source.Name, Is.EqualTo(destination.Name));
Assert.That(source.Description, Is.EqualTo(destination.Help));
}

AutoMapping test with inner object

If you have objects within objects, your test will have to ensure the data inside is correct.

Imagine the following mapping:

public class Item
{
public int Id { get; set; }
public SubItem[] SubItems { get; set; }
}

public class SubItem
{
public int Id { get; set; }
public string Name { get; set; }
}

public class DisplayItem
{
public int Id { get; set; }
public string SubItems { get; set; }
}

public class ItemToDisplayItemMapping : Profile
{
public ItemToDisplayItemMapping()
{
CreateMap<Item, DisplayItem>()
.ForMember(d => d.SubItems, opt => opt.MapFrom(s => string.Join(",", s.SubItems.Select(x => $"{x.Name} ({x.Id})"))))
.ReverseMap()
.ForMember(d => d.SubItems, opt => opt.MapFrom(s => SubItemStringToArray(s.SubItems)));
}

SubItem[] SubItemStringToArray(string subItems)
{
if (subItems != null)
{
var subItemsArray = subItems.Split(",");
List<SubItem> result = new();
subItemsArray.ToList().ForEach(subItem =>
{
var match = Regex.Match(subItem, @"(?<name>.*) \((?<id>\d+)\)");
if (match.Success)
{
int.TryParse(match.Groups["id"].Value, out int id);
var name = match.Groups["name"].Value;
result.Add(new SubItem { Id = id, Name = name });
}
});

return result.ToArray();
}

return Array.Empty<SubItem>();
}
}

Then the test of this mapping would look like this:

[Test]
public void ItemToDisplayItemTest()
{
Item item = new()
{
Id = 1,
SubItems = new[]
{
new SubItem { Id = 21, Name = "SubItem 1" },
new SubItem { Id = 22, Name = "SubItem 2" }
}
};

var displayItem = _mapper.Map<DisplayItem>(item);

Assert.That(displayItem, Is.Not.Null);
Assert.Multiple(() =>
{
Assert.That(displayItem.Id, Is.EqualTo(item.Id));
Assert.That(displayItem.SubItems, Is.EqualTo("SubItem 1 (21),SubItem 2 (22)"));
});
}

[Test]
public void DisplayItemToItemTest()
{
DisplayItem displayItem = new()
{
Id = 1,
SubItems = "SubItem 1 (21),SubItem 2 (22)"
};

var item = _mapper.Map<Item>(displayItem);

Assert.That(displayItem, Is.Not.Null);
Assert.Multiple(() =>
{
Assert.That(item.SubItems.Count, Is.EqualTo(2));
Assert.That(item.SubItems[0].Id, Is.EqualTo(21));
Assert.That(item.SubItems[0].Name, Is.EqualTo("SubItem 1"));
Assert.That(item.SubItems[1].Id, Is.EqualTo(22));
Assert.That(item.SubItems[1].Name, Is.EqualTo("SubItem 2"));
});
}

Note that in the second test, we validate the content of the array.

I hope this article gave you an idea about how to better test your code through automapping unit tests.

--

--

Valéry Raulet
All About Software Testing

I have been interested in business and technology since I was about 10. My interest spans across so many fields but I hope you’ll find my writing useful!