开发者

Help me understand what is happening with this FAIL in my unit test

开发者 https://www.devze.com 2023-01-24 07:31 出处:网络
I have a method that serializes a collection to a file using the XmlSerializer. public void Save(List<RetryAttempt> retryAttempts)

I have a method that serializes a collection to a file using the 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
  开发者_JAVA技巧      {
            fs.Close();
        }
    }

I then have another method that deserializes the collection back from the file

    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;
    }

So far so good (unless anyone spots something glaringly wrong with that code...). However, my unit test for this now fails

    [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);
    }

I would expect the list of my custom object to contain the "attempt" that I serialized to the file. Instead I am getting the following failure.

Expected: collection containing < MyNamespace.RetryManagement.RetryAttempt > But was: < MyNamespace.RetryManagement.RetryAttempt >

This message seems to suggest that instead of a collection being returned, just one object was returned. This is obviously not the case - there is a List being returned that only contains one element - I can see the collection in the immediate window and everything looks fine. I can run the test with the debugger and everything seems okay. If I simply create a collection and assert that it contains the element without saving and getting it from XML then it works fine so the point of failure must be around the serialization?


I would suspect that your class doesn't implement its own overridden version of .Equals method. The contains method would otherwise do a reference check and since you are comparing serialized versions with the original the instances are not the same.

I would suggest implementing this (along with GetHashCode so you are able to do comparisons for equality


I believe what you may be running into is the way objects are compared - in .Net, object equality is handled by comparing whether the variables in question point at the same object in memory.

in this instance, de-serializing is creating a new instance of your list with a new RetryAttempt. The new RetryAttempt may well contain the same values as the one you serialised (it should) but it will have a different memory address.

Try testing a specific property on the RetryAttempt.


Instead of having those methods write to a file I would recommend you changing the their signature to work with a TextWriter. This way they are more independent of the underlying storage:

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());
    }
}

Now your test could become:

[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
}

Also notice that you shouldn't use the GetRetryAttempts method to assert in the unit test of the Save method. Those two methods should be separate and have their separate tests.

And the GetRetryAttempts method:

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>();
}
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号