Help me understand what is happening with this FAIL in my unit test
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>();
}
精彩评论