简体   繁体   中英

Unit testing Domain model objects

In our Core domain model design, we have got a class called "Category" whose constructor is internal by design. Since the constructor is internal, when writing unit test cases I won't be able to create the object of "Category".

So my question, is it a best practice to make the constructor public just for making the "Category" class testable? Or I shouldn't be testing that "Category", instead I should have tested the Class/method responsible for creating this object?

Ta,

Rajeesh

Don't make the constructor public only for the sake of unit tests. If from a design point you decided that it should be internal, leave it that way. Test the classes that invoke this constructor.

In .NET there's the InternalsVisibleToAttribute which allows you to expose internal members to unit tests.

TDD means Test- Driven Design, and a corrolary to this is that a constructor can't really be internal "by design" if you can't test it.

Consider why it's internal. This will tell you how to address the issue. You shouldn't make the constructor public just to be able to test it, but you should consider a design that makes it easy to create new instances.

Often, constructors are made internal to protect invariants, but you could just as well achieve the same goal with a public constructor that takes required input as constructor parameters.

public class MyClass
{
    private readonly string requiredString;

    public MyClass(string requiredString)
    {
        if (requiredString == null)
        {
            throw new ArgumentNullException("requiredString");
        }
        this.requiredString = requiredString;
    }
}

Notice how the combination of the Guard Clause and the readonly keyword protects the invariant of the class. This is often a good alternative to internal constructors.

Another reason for having internal constructors is when you have a Factory Method that may return a polymorphic object, but once again, consider if it would be a problem to expose the constructor if it doesn't mean compromising invariants.

The beauty of TDD is that it forces us to take a good look at any design decision and be able to really justify each and every one of them. Consider the justification of making the constructor internal and then modfiy the API so that the type is easy to create.

Add

 [assembly: InternalsVisibleTo("UnitTestAssembly")]

to your AssemblyInfo.cs. Then UnitTestAssembl.dll is able to call your internal methods. More info is available here .

You could consider creating a static factory method that is named

Category *ConstructCategory_ForUnitTest();

with which you can create the object just for the sake of testing it.

It is apparent from the name that it should not be used outside testing context, and code review can easily spot the 'illegal' use in production grade code.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM