4

We are using AutoMapper extensively in our ASP.NET MVC web applications with the AutoMapViewResult approach set out in this question. So we have actions that look like this:

public ActionResult Edit(User item)
{
    return AutoMapView<UserEditModel>(View(item));
}

This creates hidden failure points in the application if the requested mapping has not been configured - in that this is not a compile time fail.

I'm looking at putting something in place to test these mappings. As this needs to test the actual AutoMapper configuration I presume this should be done as part of integration testing? Should these tests be structured per controller or per entity? What about the possibility of automatically parsing all calls to AutoMapView?

Note that we are already testing that the AutoMapper configuration is valid using AssertConfigurationIsValid, it is missing mappings that I want to deal with.

Community
  • 1
  • 1
Rob West
  • 5,189
  • 1
  • 27
  • 42
  • Couldn't you just write Unit tests for your action methods? Am I missing something? – Brook Jun 24 '11 at 11:45
  • @Brook - this can't really be tested by a unit test for the action because it involves external code, e.g. the actual AutoMapper configuration. Normal unit tests mock out the AutoMapper. – Rob West Jun 24 '11 at 12:20
  • which is why you should be testing your Automapper configuration before you write code that depends on them. Integration tests always follow unit tests. – Ben Foster Jun 24 '11 at 12:37

4 Answers4

4

If your controller action looked like this:

public AutoMapView<UserEditModel> Edit(User item)
{
    return AutoMapView<UserEditModel>(View(item));
}

Then you can pretty easily, using reflection, look for all controller actions in your project. You then examine the action parameter types and the generic type parameter of your AutoMapView action result. Finally, you ask AutoMapper if it has a type map for those input/output models. AutoMapper doesn't have a "CanMap" method, but you can use the IConfigurationProvider methods of FindTypeMapFor:

((IConfigurationProvider) Mapper.Configuration).FindTypeMapFor(null, typeof(User), typeof(UserEditModel);

Just make sure that's not null.

Jimmy Bogard
  • 26,045
  • 5
  • 74
  • 69
0

I do something like this.

using System.Linq;
using System.Reflection;
using AutoMapper;
using Microsoft.VisualStudio.TestTools.UnitTesting;

public class SampleDto
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

public class Sample
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string LoginId { get; set; }
}

public class AutomapperConfig
{
    public static void Configure()
    {
        Mapper.Initialize(cfg => cfg.AddProfile<ViewModelProfile>());
    }
}

public class ViewModelProfile : Profile
{
    protected override void Configure()
    {
        CreateMap<SampleDto, Sample>();
    }
}

[TestClass]
public class AutoMapperTestsSample
{
    public AutoMapperTestsSample()
    {
        AutomapperConfig.Configure();
    }


    [TestMethod]
    public void TestSampleDtoFirstName()
    {
        #region Arrange
        var source = new SampleDto();
        source.FirstName = "Jim";
        //source.LastName = "Bob";
        var dest = new Sample();
        dest.FirstName = "FirstName";
        dest.LastName = "LastName";
        dest.LoginId = "LoginId";
        #endregion Arrange

        #region Act
        AutoMapper.Mapper.Map(source, dest);
        #endregion Act

        #region Assert
        Assert.AreEqual("Jim", dest.FirstName);
        Assert.AreEqual(null, dest.LastName);
        Assert.AreEqual("LoginId", dest.LoginId);
        #endregion Assert       
    }

    [TestMethod]
    public void TestSampleDtoLastName()
    {
        #region Arrange
        var source = new SampleDto();
        //source.FirstName = "Jim";
        source.LastName = "Bob";
        var dest = new Sample();
        dest.FirstName = "FirstName";
        dest.LastName = "LastName";
        dest.LoginId = "LoginId";
        #endregion Arrange

        #region Act
        AutoMapper.Mapper.Map(source, dest);
        #endregion Act

        #region Assert
        Assert.AreEqual(null, dest.FirstName);
        Assert.AreEqual("Bob", dest.LastName);
        Assert.AreEqual("LoginId", dest.LoginId);
        #endregion Assert
    }

    /// <summary>
    /// This lets me know if something changed in the Dto object so I know to adjust my tests
    /// </summary>
    [TestMethod]
    public void TestSampleDtoReflection()
    {
        #region Arrange
        var xxx = typeof(SampleDto);
        #endregion Arrange

        #region Act
        #endregion Act

        #region Assert
        Assert.AreEqual(2, xxx.GetRuntimeFields().Count());
        Assert.AreEqual("System.String", xxx.GetRuntimeFields().Single(a => a.Name.Contains("FirstName")).FieldType.ToString());
        Assert.AreEqual("System.String", xxx.GetRuntimeFields().Single(a => a.Name.Contains("LastName")).FieldType.ToString());            
        #endregion Assert       
    }
}
0

You can use the AssertConfigurationIsValid method. Details are on the automapper codeplex site (http://automapper.codeplex.com/wikipage?title=Configuration%20Validation)

Strictly speaking you should be writing a test to validate the mapping before you write a controller action that depends on the mapping configuration being present.

Either way, you can use the Test Helpers in the MvcContrib project to check the action method returns the expected ViewResult and Model.

Here's an example:

            pageController.Page("test-page")
            .AssertViewRendered()
                .WithViewData<PortfolioViewData>()
                    .Page
                        .ShouldNotBeNull()
                        .Title.ShouldEqual("Test Page");
Ben Foster
  • 34,340
  • 40
  • 176
  • 285
  • You are missing the point - as stated in the question I am already using that to validate the configuration, what I am looking for is something to flag up mappings which my application is requesting which are not configured – Rob West Jun 24 '11 at 12:13
  • Yes we should be writing something to verify the mapping, but developers forgot and I am looking for something to mitigate this risk. – Rob West Jun 24 '11 at 12:48
  • So does my update help? This would throw if you hadn't configured the mapping. – Ben Foster Jun 24 '11 at 13:28
0
    [Test]
    public void MapperConfiguration()
    {
        var mapper = Web.Dto.Mapper.Instance;
        AutoMapper.Mapper.AssertConfigurationIsValid();
    }
alexl
  • 6,841
  • 3
  • 24
  • 29