NUnit 与 Assert.AreEqual 不能很好地配合

发布于 2024-08-03 16:50:06 字数 1624 浏览 6 评论 0原文

我是单元测试的新手,尤其是 NIt。 我只是从书中输入一些涉及 Java 和 JUnit 的示例。但我改用 C#。

问题是:我有一个具有重写方法的类,例如 Equals()GetHashCode(),但是当我尝试将此类的两个对象与Assert.AreEqual() 我的代码没有被调用,所以我得到了一个异常。

Assert.True(MyClass.Equals(MyClass2)) 效果很好。但我不想使用此构造来代替 Assert.AreEqual()。问题可能出在哪里?

这是类:

public class Money
{
    public int amount;
    protected string currency;

    public Money(int amount, string currency)
    {
        this.amount = amount;
        this.currency = currency;
    }

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

        Money money = (Money)obj;
        return (amount == money.amount)
                && (Currency().Equals(money.Currency()));
    }

    public new int GetHashCode()
    {
        return (string.Format("{0}{1}", amount, currency)).GetHashCode();
    }

    public static Money Dollar(int amount)
    {
        return new Money(amount, "USD");
    }
    public static Money Franc(int amount)
    {
        return new Money(amount, "CHF");
    }

    public Money Times(int multiplier)
    {
        return new Money(amount * multiplier, currency);
    }

    public string Currency()
    {
        return currency;
    }
}

以及测试方法本身:

[TestFixture]
public class DollarTest
{
    [Test]
    public void TestMultiplication()
    {
        Money five = Money.Dollar(5);
        Assert.True(Money.Dollar(10).Equals(five.Times(2)));  // ok
        Assert.AreEqual(Money.Dollar(10), five.Times(2));     // fails
    }
}

I'm new to unit testing and NUit in particular.
I'm just typing some examples from the book which refers to Java and JUnit. But I'm using C# instead.

The problem is: I've got a class with overriden methods such as Equals() and GetHashCode(), but when I am trying to compare two objects of this class with Assert.AreEqual() my code is not called, so I get an exception.

Assert.True(MyClass.Equals(MyClass2)) does work well. But I don't want to use this construction instead of Assert.AreEqual(). Where can the problem be?

Here is the class:

public class Money
{
    public int amount;
    protected string currency;

    public Money(int amount, string currency)
    {
        this.amount = amount;
        this.currency = currency;
    }

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

        Money money = (Money)obj;
        return (amount == money.amount)
                && (Currency().Equals(money.Currency()));
    }

    public new int GetHashCode()
    {
        return (string.Format("{0}{1}", amount, currency)).GetHashCode();
    }

    public static Money Dollar(int amount)
    {
        return new Money(amount, "USD");
    }
    public static Money Franc(int amount)
    {
        return new Money(amount, "CHF");
    }

    public Money Times(int multiplier)
    {
        return new Money(amount * multiplier, currency);
    }

    public string Currency()
    {
        return currency;
    }
}

And the test method itself:

[TestFixture]
public class DollarTest
{
    [Test]
    public void TestMultiplication()
    {
        Money five = Money.Dollar(5);
        Assert.True(Money.Dollar(10).Equals(five.Times(2)));  // ok
        Assert.AreEqual(Money.Dollar(10), five.Times(2));     // fails
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

忆依然 2024-08-10 16:50:06

问题是您隐藏 Equals,而不是覆盖它。干得好 - 你的单元测试发现了一个错误:)

你的代码应该是:(

public override bool Equals(object obj)
{
    Money money = obj as Money;
    if (money == null)
        return false;

    return (amount == money.amount && currency == money.currency);
}

如果你给它错误的类型,这也将防止它抛出异常。)

我也使字符串相等测试更简单 - 运算符重载可能会非常有帮助:)

顺便说一句,您几乎肯定希望:

  • Currency 更改为属性,而不是方法
  • 添加 Amount 属性
  • 可能会更改 Amount 的类型code>amount 为 decimal 而不是 int
  • 将字段设为私有且只读
  • 密封类
  • 为 == 和 != 添加运算符重载
  • 可能添加 * 运算符重载以执行与 Times 相同的操作
  • 在计算哈希时避免字符串格式(有数十个答案显示更好的哈希实现)

编辑:我刚刚重读您正在使用书中的示例。这本书真的隐藏而不是重写 Equals 方法吗?如果是的话,我建议你买一本新书(除非它是一个故意的例子,说明什么时候使用隐藏是错误的!)...是哪本书?

The problem is you're hiding Equals, not overriding it. Well done - your unit test has found a bug :)

Your code should be:

public override bool Equals(object obj)
{
    Money money = obj as Money;
    if (money == null)
        return false;

    return (amount == money.amount && currency == money.currency);
}

(This will prevent it from throwing an exception if you give it the wrong type, too.)

I've made the string equality test simpler too - operator overloading can be very helpful :)

By the way, you almost certainly want to:

  • Change Currency to be a property, not a method
  • Add an Amount property
  • Probably change the type of amount to be decimal instead of int
  • Make the fields private and readonly
  • Seal the class
  • Add operator overloads for == and !=
  • Possibly add a * operator overload to do the same as Times
  • Avoid string formatting when calculating the hash (there are dozens of answers showing better hash implementations)

EDIT: I've just reread that you're using an example from a book. Does the book really hide instead of overriding the Equals method? I suggest you get a new book, if so (unless it's being a deliberate example of when it's wrong to use hiding!)... which book is it?

郁金香雨 2024-08-10 16:50:06

我发现实现 IEquatable 接口(它也有一个

Equals(T other)

方法)给我带来了与上述相同的问题,这令人困惑。

我选择使用上面的 IEquaytable 接口覆盖 Equals 方法的唯一原因是不必进行类型检查。

最后我不得不使用下面的代码

public bool Equals(CustomTag other)
{
   return (other.Name.Trim().ToLower() == Name.Trim().ToLower());
}

public override bool Equals(object o)
{
    if (o is CustomTag)
    {
        return Equals(o as CustomTag);
    }
    return false;
}

,但后来我想,为什么不保留 IEquatable 接口的原样,而只重写 Equals 方法。 (更少的代码=更好)

I found it confusing that implementing the IEquatable interface, which also has an

Equals(T other)

method, posed me with the same problem as described above.

The only reason I chose to use the IEquaytable interface above overriding the Equals method was not to have to do the type check.

In the end I had to use the following code

public bool Equals(CustomTag other)
{
   return (other.Name.Trim().ToLower() == Name.Trim().ToLower());
}

public override bool Equals(object o)
{
    if (o is CustomTag)
    {
        return Equals(o as CustomTag);
    }
    return false;
}

but then I thought, why not just leave the IEquatable interface for what it is and only override the Equals method. (less code = better)

梓梦 2024-08-10 16:50:06

我怀疑你的问题是你没有 overridden 重载 equal == 运算符。在幕后 Assert.AreEqual 可能使用 ==。

请参阅运算符重载教程

更新:我通过调试器运行了 NUnit 测试,它确实使用了 Equals 方法而不是 == 运算符。

I suspect your problem is that you haven't overridden overload the equality == operator. Under the hood the Assert.AreEqual is probably using ==.

See Operator Overloading Tutorial.

Update: I ran the NUnit test through the debugger and it does indeed use the Equals method and not the == operator.

相思故 2024-08-10 16:50:06

您可以使用名为 Should 的库编写与框架无关的断言。它还具有非常好的流畅语法,如果您喜欢流畅的界面,可以使用它。我有一篇与此相关的博客文章。

http://nileshgule.blogspot.com/2010 /11/use-should-assertion-library-to-write.html

You can write framework agnostic asserts using a library called Should. It also has a very nice fluent syntax which can be used if you like fluent interfaces. I had a blog post related to the same.

http://nileshgule.blogspot.com/2010/11/use-should-assertion-library-to-write.html

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文