简体   繁体   English

单元测试域模型对象

[英]Unit testing Domain model objects

In our Core domain model design, we have got a class called "Category" whose constructor is internal by design. 在我们的Core域模型设计中,我们有一个名为“Category”的类,其构造函数是内部设计的。 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 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. 在.NET中有InternalsVisibleToAttribute ,它允许您将内部成员公开给单元测试。

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. TDD意味着测试驱动设计,并且对此的证据是,如果您无法对其进行测试,那么构造函数就不能真正“内部设计”。

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. 注意Guard子句和readonly关键字的组合如何保护类的不变量。 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. TDD的美妙之处在于它迫使我们好好看看任何设计决策,并能够真正证明每一个设计决策的合理性 Consider the justification of making the constructor internal and then modfiy the API so that the type is easy to create. 考虑使构造函数内部化然后修改API以使类型易于创建的理由。

Add

 [assembly: InternalsVisibleTo("UnitTestAssembly")]

to your AssemblyInfo.cs. 到你的AssemblyInfo.cs。 Then UnitTestAssembl.dll is able to call your internal methods. 然后UnitTestAssembl.dll能够调用您的内部方法。 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. 从名称中可以明显看出,它不应该在测试环境之外使用,代码审查可以很容易地发现生产等级代码中的“非法”使用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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