c# - NUnit CollectionAssert.AreEqual(expected,actual) vs Assert.IsTrue(expected.SequenceEqual(actual))

标签 c# linq collections nunit assertions

我有一些对象被放入队列中。队列中的所有对象都实现相同的基接口(interface),这也要求它们实现 IEquatable<>。

我想验证是否以正确的顺序将正确的对象放入队列中。

当我编写一个断言 CollectionAssert.AreEqual(expected,actual) 的测试时,测试失败,说明虽然队列是预期长度,但它在索引 0 处不同。

但是,当我将测试断言写为 Assert.IsTrue(expected.SequenceEqual(actual)) 时,测试通过了。

在我看来,这两个断言应该是相同的,但显然它们是完全不同的。

NUnit 的网站对集合断言方法的介绍不是很详细,而 Linq 文档虽然更详细,但如果无法与 NUnit 使用集合断言方法进行比较,也无济于事。

这两个断言有何不同?

编辑 - 添加细节

这是被测代码以及我希望得到相同结果的两个测试。

public enum ArgumentTypeEnum
{
    SpiceworksDbName,
    DestinationDbName,
    DestinationServerName
}

public interface IArgument : IEquatable<IArgument>
{
}

public interface ICommandArgument : IArgument
{
    ArgumentTypeEnum ArgumentType { get; }
}

internal interface IValueArgument : IArgument
{
    String ArgumentValue { get; }
}

public class CommandArgument : ICommandArgument
{
    public CommandArgument(ArgumentTypeEnum argumentType) {
        ArgumentType = argumentType;
    }

    public ArgumentTypeEnum ArgumentType { get; private set; }

    public bool Equals(IArgument other)
    {
        if (other == null)
        {
            return false;
        }

        var otherAsCommandArg = other as CommandArgument;
        if (otherAsCommandArg == null)
        {
            return false;
        }

        return ArgumentType == otherAsCommandArg.ArgumentType;
    }
}

public class ValueArgument : IValueArgument
{
    public ValueArgument(String argumentValue)
    {
        ArgumentValue = argumentValue;
    }

    public string ArgumentValue { get; private set; }

    public bool Equals(IArgument other)
    {
        if (other == null)
        {
            return false;
        }

        var otherAsValueArg = other as ValueArgument;
        if (otherAsValueArg == null)
        {
            return false;
        }

        return ArgumentValue == otherAsValueArg.ArgumentValue;
    }
}

public class Tokenizer
{
     public Queue<IArgument> TokenizeArguments(string[] args) {
        var tokenQueue = new Queue<IArgument>();
        args.ToList().ForEach((arg) => {
                if (arg.StartsWith("-"))
                {
                    switch (arg)
                    {
                        case "-sd":
                            tokenQueue.Enqueue(new CommandArgument(ArgumentTypeEnum.SpiceworksDbName));
                            break;
                        case "-dd":
                            tokenQueue.Enqueue(new CommandArgument(ArgumentTypeEnum.DestinationDbName));
                            break;
                        case "-ds":
                            tokenQueue.Enqueue(new CommandArgument(ArgumentTypeEnum.DestinationServerName));
                            break;
                        default:
                            tokenQueue.Enqueue(new ValueArgument(arg));
                            break;
                    }
                }
                else
                {
                    tokenQueue.Enqueue(new ValueArgument(arg));
                }
            });
        return tokenQueue;
    }
}

[TestFixture]
public class TokenizerSpecs
{
    ///Passes
    [Test] 
    public void Tokenizer_MultipleCommandsAndValues_TokenizesAsExpected1() {
        var args = new[]
        {
            "-sd", @"\\some\Directory\foo.db", "-dd", "some database name", "-ds", "Server.name", "somerandomarg",
            "-unreconized"
        };
        var t = new Tokenizer();
        var actualResult = t.TokenizeArguments(args);

        var expectedResult = new Queue<IArgument>();
        expectedResult.Enqueue(new CommandArgument(ArgumentTypeEnum.SpiceworksDbName));
        expectedResult.Enqueue(new ValueArgument(@"\\some\Directory\foo.db"));
        expectedResult.Enqueue(new CommandArgument(ArgumentTypeEnum.DestinationDbName));
        expectedResult.Enqueue(new ValueArgument("some database name"));
        expectedResult.Enqueue(new CommandArgument(ArgumentTypeEnum.DestinationServerName));
        expectedResult.Enqueue(new ValueArgument("Server.name"));
        expectedResult.Enqueue(new ValueArgument("somerandomarg"));
        expectedResult.Enqueue(new ValueArgument("-unreconized"));

        Assert.IsTrue(expectedResult.SequenceEqual(actualResult));
    }

    ///Fails
    [Test]
    public void Tokenizer_MultipleCommandsAndValues_TokenizesAsExpected2()
    {
        var args = new[]
        {
            "-sd", @"\\some\Directory\foo.db", "-dd", "some database name", "-ds", "Server.name", "somerandomarg",
            "-unreconized"
        };
        var t = new Tokenizer();
        var actualResult = t.TokenizeArguments(args);

        var expectedResult = new Queue<IArgument>();
        expectedResult.Enqueue(new CommandArgument(ArgumentTypeEnum.SpiceworksDbName));
        expectedResult.Enqueue(new ValueArgument(@"\\some\Directory\foo.db"));
        expectedResult.Enqueue(new CommandArgument(ArgumentTypeEnum.DestinationDbName));
        expectedResult.Enqueue(new ValueArgument("some database name"));
        expectedResult.Enqueue(new CommandArgument(ArgumentTypeEnum.DestinationServerName));
        expectedResult.Enqueue(new ValueArgument("Server.name"));
        expectedResult.Enqueue(new ValueArgument("somerandomarg"));
        expectedResult.Enqueue(new ValueArgument("-unreconized"));

        CollectionAssert.AreEqual(expectedResult, actualResult);
    }
}

最佳答案

我已经查看了 NUnit 的源代码,看来您这里有一个错误。比较由 NUnitEqualityComparer.EnumerablesEqual 完成,随后通过 NUnitEqualityComparer.ObjectsEqual 比较每个元素。我们可以使用这个对象做简单的测试:

var n = new NUnitEqualityComparer();
var tolerance = Tolerance.Zero;
var equal = n.AreEqual(new CommandArgument(ArgumentTypeEnum.SpiceworksDbName),
                       new CommandArgument(ArgumentTypeEnum.SpiceworksDbName),
                       ref tolerance);

这个测试返回false!

不知何故,ObjectsEqual 并没有在对象的 Equals 方法中结束。需要对源代码进行调试才能找出原因,但这个测试足以证明存在错误。

关于c# - NUnit CollectionAssert.AreEqual(expected,actual) vs Assert.IsTrue(expected.SequenceEqual(actual)),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26390953/

相关文章:

ios - 如何检查collectionview是否为空xcode

c# - 在 Xna/MonoGame 中按程序生成 Texture2D

c# - 如何在 TextBox Windows Phone 8.1 中更改文本的垂直对齐方式

c# - 降级到 .net 3.5 后找不到 Linq

linq - Enumerable.ToDictionary 是否只检索它需要的内容?

java - Java 中是否有固定大小的 Deque 可以删除旧元素?

c# - 删除命名空间标签(xmlns :) from XMLSerializer

c# - C#Windows Phone Mango-无效的跨线程访问?解析XML

c# - 如何使用 Linq 按日期对列表列表进行分组?

scala - 在 Scala 中设计一个方便的默认值映射