我应该使用IEquatable缓解工厂测试? [英] Should I be using IEquatable to ease testing of factories?

查看:157
本文介绍了我应该使用IEquatable缓解工厂测试?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我常与表示从工厂生产的实体类的工作。
为了让我的工厂进行简单的测试很容易,我通常实施 IEquatable< T> ,同时也覆盖的GetHashCode 等于(用的 MSDN

I often work with classes that represent entities produced from a factory. To enable easy testing of my factories easily I usually implement IEquatable<T>, whilst also overriding GetHashCode and Equals (as suggested by the MSDN).

例如;采取何种简化作示例如下实体类。通常情况下我的课有一堆更多的属性。偶尔有一个还集合,在我检查使用 SequenceEqual 等于方法。

For example; take the following entity class which is simplified for example purposes. Typically my classes have a bunch more properties. Occasionally there is a also collection, which in the Equals method I check using SequenceEqual.

public class Product : IEquatable<Product>
{
    public string Name
    {
        get;
        private set;
    }

    public Product(string name)
    {
        Name = name;
    }

    public override bool Equals(object obj)
    {
        if (obj == null)
        {
            return false;
        }

        Product product = obj as Product;

        if (product == null)
        {
            return false;
        }
        else
        {
            return Equals(product);
        }
    }

    public bool Equals(Product other)
    {
        return Name == other.Name;
    }

    public override int GetHashCode()
    {
        return Name.GetHashCode();
    }
}

这意味着然后我可以做简单的单元测试,像这样(假设构造别处测试)。

This means I can then do simple unit tests like so (assuming the constructor is tested elsewhere).

[TestMethod]
public void TestFactory()
{
    Product expected = new Product("James");

    Product actual = ProductFactory.BuildJames();

    Assert.AreEqual(expected, actual);
}



然而,这引起了一些问题。

However this raises a number of questions.


  1. 的GetHashCode 未实际使用,但我花了时间实现它。

  2. 我实际上很少想在我的测试以外实际应用使用等于

  3. 我花更多的时间写更多的测试,以确保等于实际工作正常。

  4. 我现在有另外三个方法来维持,例如:属性添加到类,更新的方法。

  1. GetHashCode isn't actually used but I've spent time implementing it.
  2. I rarely actually want to use Equals in my actual application beyond testing.
  3. I spend more time writing more tests to ensure the Equals actually works correctly.
  4. I now have another three methods to maintain, e.g. add a property to the class, update methods.

不过,这确实给了我一个非常整洁的 TestMethod的

But, this does give me a very neat TestMethod.

这是一个合适的使用 IEquatable ,还是应该采取另一种方法?

Is this an appropriate use of IEquatable, or should I take another approach?

推荐答案

这是否是一个好主意,或者没有真正要看是什么样键入您的工厂创建的。有两种类型:

Whether this is a good idea or not really depends on what kind of type your factory creates. There are two kinds of types:


  • 值语义的类型(值类型的简称)以及

  • Types with value semantics (value types for short) and

引用语义类型(引用类型的简称。)

Types with reference semantics (reference types for short.)

在C#是很常见的使用结构值类型和对于引用类型,但你没有的话,你可以使用两种。问题的关键在于:

In C# it is common to use struct for value types and class for reference types, but you do not have to, you may use class for both. The point is that:


  • 值类型,目的是要小,一般不可变的,自包含的对象,其主要目的是含有一定价值,而

  • Value types are meant to be small, usually immutable, self-contained objects whose main purpose is to contain a certain value, while

引用类型是具有复杂的可变状态对象,对其他对象可能引用和非平凡的功能,即算法,商业逻辑等。

Reference types are objects that have complex mutable state, possibly references to other objects, and non-trivial functionality, i.e. algorithms, business logic, etc.

如果您的工厂创造的价值类型,然后确定,继续前进,使之 IEquatable 并使用这一技巧。但在大多数情况下,我们不使用工厂值类型,这往往是相当琐碎,我们使用工厂对于引用类型,这往往是相当复杂的,所以如果你的工厂建立一个引用类型,那么真,这些类型的对象只是为了参照进行比较,所以加入等于()的GetHashCode()方法是在任何地方从误导错误。

If your factory is creating a value type, then sure, go ahead and make it IEquatable and use this neat trick. But in most cases, we don't use factories for value types, which tend to be rather trivial, we use factories for reference types, which tend to be rather complex, so if your factory is creating a reference type, then really, these kinds of objects are only meant to be compared by reference, so adding Equals() and GetHashCode() methods is anywhere from misleading to wrong.

乘坐从什么用哈希映射出现一个提示:的存在等于()的GetHashCode()在类型一般意味着你可以使用这种类型作为哈希映射中的键的实例;但是,如果对象不是不可变值类型,则它的状态可以是已被放置在地图上之后,在这种情况下,在 GetHashCode()方法方法将开始评估改变别的东西,但哈希映射永远不会打扰重新调用的GetHashCode(),以重新定位地图中的对象。在这种情况下,结果往往是混乱。

Take a hint from what happens with hash maps: the presence of Equals() and GetHashCode() in a type generally means that you can use an instance of this type as a key in a hash map; but if the object is not an immutable value type, then its state may change after it has been placed in the map, in which case the GetHashCode() method will start evaluating to something else, but the hash map will never bother re-invoking GetHashCode() in order to re-position the object in the map. The result in such cases tends to be chaos.

所以,底线是,如果你的工厂创建复杂的对象,那么你或许应该采取不同的方法。显而易见的解决方案是调用工厂,然后检查返回的对象的每个属性,以确保它们都如预期。

So, the bottom line is that if your factory creates complex objects, then you should perhaps take a different approach. The obvious solution is to invoke the factory and then check each property of the returned object to make sure they are all as expected.

我也许可以提出一个改进这一点,虽然要小心,我只是想到这一点,我从来没有尝试过,所以它可以或不可以变成是一个在实践好主意。在这里,它是:

I could perhaps propose an improvement to this, though beware that I just thought of it, I have never tried it, so it may and may not turn out to be a good idea in practice. Here it is:

您大概工厂创建实现特定接口的对象。 (否则,什么是有一个工厂的角度来看,对吧?)所以,理论上你可以规定,实现这个接口应该有初始化为一组特定值的某些属性的对象是新创建的实例。这将是在接口强加的规则,所以你可以有一些功能依赖于它检查是否属实的接口,这个功能甚至可以与一些提示,希望根据不同的情况不同的初始值参数化。

Your factory presumably creates objects that implement a particular interface. (Otherwise, what's the point of having a factory, right?) So, you could in theory stipulate that newly created instances of objects that implement this interface should have certain properties initialized to a particular set of values. This would be a rule imposed by the interface, so you could have some function tied to the interface which checks whether this is true, and this function could even be parametrized with some hint as to expect different initial values under different circumstances.

(上次我检查,在C#捆绑接口的方法通常是一个的扩展方法的;我不记得关闭我的头顶C#是否允许静态方法来定,还是C#的设计者还没有加入到语言的东西一样整洁,优雅如Java的默认接口方法的接口的一部分。)

(Last I checked, in C# a method tied to an interface was usually an extension method; I do not remember off the top of my head whether C# allows static methods to be part of an interface, or whether the designers of C# have yet added to the language something as neat and elegant as the default interface methods of Java.)

所以,用一个扩展方法,它也许可以是这样的:

So, with an extension method, it could perhaps look like this:

public boolean IsProperlyInitializedInstance( this IProduct self, String hint )
{
    if( self.Name != hint )
        return false;
    //more checks here
    return true;
}

IProduct product = productFactory.BuildJames();
Assert.IsTrue( product.IsProperlyInitializedInstance( hint:"James" ) );

这篇关于我应该使用IEquatable缓解工厂测试?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆