Question

We have the object

public class MyObject{
    protected MyObject(){}

    public string Property1 {get;private set;}
    public string Property2 {get;private set;}
    public string Property3 {get;private set;}
    public string Property4 {get;private set;}
    public string Property5 {get;private set;}
    public string Property6 {get;private set;}
    public string Property7 {get;private set;}
    public string Property8 {get;private set;}
    public string Property9 {get;private set;}
    public string Property10 {get;private set;}
}

In our production code we populate this object through automapper. It can access the properties and set them correctly.

Now when we want to test this class in a future pipeline it is not possible to populate the properties with dummy values (to be tested against).

There are a few options available.

  • Custom constructors to accept the parameters required for the tests and set the properties, currently 3 constructors are required. This is not clean since the constructors do not serve any business functionality.

  • Make the properties virtual so the class can be stubbed. But marking the properties virtual does not provide any business value and pollute my class.

  • Add an object builder to the class to internally construct the object. Again no added business value. Perhaps a bit cleaner but still a lot of non relevant code in the domain objects.

Any suggestions, advice or alternative options here?

Was it helpful?

Solution

You have a number of options.

  • Go ahead and use custom constructors, virtual properties, or an object builder. The rationale behind this is that an object should stand on its own, and not depend on some magic like the automapper. A class which is completely useless unless there is some magic going on is not a very well thought of class. "Business value" is not the only determinant of a good design.

  • Include the automapper in the testing process. Some will say this is not a unit test anymore. It does not matter. Unit testing is not the only kind of testing.

  • Implement something which provides the functionality of automapper specifically for testing. You can easily write a little utility which will use reflection to populate your object from a dictionary containing property names and values.

Also take a look at this question & answer: Would you rather make private stuff internal/public for tests, or use some kind of hack like PrivateObject?

OTHER TIPS

I don't hesitate to use reflection for things like this in tests.

I dislike making things virtual for mocking as it changes the code for the wrong reason.

I don't know automapper but I agree with @Mike that including it in the tests can be a good idea. The distinction unit test / integration test is not very interesting imo. Sure if the test suite is getting big and slow you will need to filter and classify things to run only a sensible subset of all tests at the highest frequency.

Sample hack using reflection, using nameof() will have better perf but then you loose types.:

public static class TestExtensions
{
    public static void SetProperty<TSource, TProperty>(
        this TSource source,
        Expression<Func<TSource, TProperty>> prop,
        TProperty value)
    {
        var propertyInfo = (PropertyInfo)((MemberExpression)prop.Body).Member;
        propertyInfo.SetValue(source, value);
    }
}

For unit testing purpose, make use of mocking frameworks like Microsoft Fakes, TypeMock and JustMock which provides support for mocking private members.

Please have a look at Smocks (avaiable @nuget packages) also. Limitation of Smocks is, it will not provide access to private members. But it has ability to mock static and non-virtual members. Also it is available for free of cost.

Another simplest way is to use, PrivateObject / PrivateType.

Licensed under: CC-BY-SA with attribution
scroll top