在我的单元测试中帮助我了解这个失败的情况

时间:2010-11-09 09:17:13

标签: c# xml unit-testing

我有一个使用XmlSerializer将集合序列化为文件的方法。

    public void Save(List<RetryAttempt> retryAttempts)
    {
        FileStream fs = new FileStream(this.fileName, FileMode.Create);

        try
        {
            XmlSerializer xmlSerializer = new XmlSerializer(typeof(List<RetryAttempt>));
            xmlSerializer.Serialize(fs, retryAttempts);
        }
        catch (Exception ex)
        {
            LocalLogger.LogError("Unable to save retry information to xml file.", ex.ToString());
        }
        finally
        {
            fs.Close();
        }
    }

然后我有另一个方法从文件

反序列化集合
    public List<RetryAttempt> GetRetryAttempts()
    {
        List<RetryAttempt> retryAttempts = new List<RetryAttempt>();

        if (File.Exists(this.fileName))
        {
            FileStream fs = new FileStream(this.fileName, FileMode.Open);

            try
            {
                XmlSerializer xmlSerializer = new XmlSerializer(typeof(List<RetryAttempt>));
                retryAttempts = (List<RetryAttempt>)xmlSerializer.Deserialize(fs);
            }
            catch (Exception ex)
            {
                LocalLogger.LogError("Unable to read from retry xml file.", ex.ToString());
            }
            finally
            {
                fs.Close();
            }
        }

        return retryAttempts;
    }

到目前为止一切顺利(除非有人发现代码明显错误......)。但是,我的单元测试现在失败了

    [Test]
    public void GetRetryAttempts_AttemptsExist_ListOfAttemptsReturned()
    {
        this.attempt = new RetryAttempt("1234", 4);
        this.attempts = new List<RetryAttempt>() { attempt };
        this.xmlStore = new XmlRetryFileStore(RetryType.Download);
        xmlStore.Save(attempts);

        List<RetryAttempt> savedAttempts = xmlStore.GetRetryAttempts();
        Assert.Contains(attempt, savedAttempts);
    }

我希望我的自定义对象列表包含我序列化到文件的“尝试”。相反,我得到以下失败。

预期:包含&lt;的集合MyNamespace.RetryManagement.RetryAttempt&gt;   但是:&lt; MyNamespace.RetryManagement.RetryAttempt&gt;

此消息似乎表明,只返回一个对象,而不是返回一个集合。显然不是这种情况 - 返回的List只包含一个元素 - 我可以在即时窗口中看到集合,一切看起来都很好。我可以使用调试器运行测试,一切似乎都没问题。如果我只是创建一个集合并声明它包含元素而不保存并从XML中获取它然后它工作正常,那么失败点必须围绕序列化?

3 个答案:

答案 0 :(得分:3)

我怀疑你的类没有实现自己的.Equals方法的重写版本。否则contains方法会进行引用检查,因为您将序列化版本与原始版本进行比较,实例不一样。

我建议实施此功能(以及GetHashCode,以便您可以进行相等比较

答案 1 :(得分:1)

我相信你可能遇到的是比较对象的方式 - 在.Net中,通过比较有问题的变量是否指向内存中的同一对象来处理对象相等性。

在这种情况下,反序列化是使用新的RetryAttempt创建列表的新实例。新的RetryAttempt可能包含与您序列化的值(它应该)相同的值,但它将具有不同的内存地址。

尝试在RetryAttempt上测试特定属性。

答案 2 :(得分:1)

我建议您更改其签名以使用TextWriter,而不是将这些方法写入文件。这样他们就更加独立于底层存储:

public void Save(List<RetryAttempt> retryAttempts, TextWriter writer)
{
    try
    {
        XmlSerializer xmlSerializer = new XmlSerializer(typeof(List<RetryAttempt>));
        xmlSerializer.Serialize(writer, retryAttempts);
    }
    catch (Exception ex)
    {
        LocalLogger.LogError("Unable to save retry information to xml file.", ex.ToString());
    }
}

现在你的测试可能会变成:

[TestMethod]
public void TestSerialize()
{
    // arrange
    var sb = new StringBuilder();
    using (var writer = new StringWriter(sb))
    {
        this.attempt = new RetryAttempt("1234", 4);
        this.attempts = new List<RetryAttempt>() { attempt };
        this.xmlStore = new XmlRetryFileStore(RetryType.Download);
        this.xmlStore.Save(writer, this.attempts);
    }

    string actual = sb.ToString();
    // TODO: assert on the resulting XML
}

另请注意,不应使用GetRetryAttempts方法在Save方法的单元测试中断言。这两种方法应该是分开的,并进行单独的测试。

GetRetryAttempts方法:

public List<RetryAttempt> GetRetryAttempts(TextReader reader)
{
    try
    {
        XmlSerializer xmlSerializer = new XmlSerializer(typeof(List<RetryAttempt>));
        return (List<RetryAttempt>)xmlSerializer.Deserialize(reader);
    }
    catch (Exception ex)
    {
        LocalLogger.LogError("Unable to read from retry xml file.", ex.ToString());
    }
    return new List<RetryAttempt>();
}