C# 帮助我了解单元测试失败的原因
我有一个使用XmlSerializer将集合序列化为文件的方法C# 帮助我了解单元测试失败的原因,c#,xml,unit-testing,C#,Xml,Unit Testing,我有一个使用XmlSerializer将集合序列化为文件的方法 public void Save(List<RetryAttempt> retryAttempts) { FileStream fs = new FileStream(this.fileName, FileMode.Create); try { XmlSerializer xmlSerializer = new XmlSeriali
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);
}
我希望自定义对象的列表包含我序列化到该文件的尝试。相反,我得到了以下失败
应为:包含这条消息似乎表明返回的不是集合,而是一个对象。显然不是这样的-返回的列表只包含一个元素-我可以在即时窗口中看到集合,一切看起来都很好。我可以用调试器运行测试,一切似乎都正常。如果我只是创建一个集合并断言它包含元素,而不保存它并从XML获取它,那么它工作得很好,所以失败点一定在序列化附近 我怀疑您的类没有实现自己的.Equals方法的重写版本。否则,contains方法将执行引用检查,因为您正在将序列化版本与原始版本进行比较,所以实例不相同
我建议将其与GetHashCode一起实现,这样您就可以对相等进行比较我相信您可能遇到的是对象比较的方式-在.Net中,对象相等是通过比较问题中的变量是否指向内存中的同一对象来处理的 在本例中,反序列化是使用新的RetryAttenting创建列表的新实例。新的retrytry可能包含与序列化的值相同的值,但它将具有不同的内存地址
尝试在RetryAttement上测试特定属性。与其让这些方法写入文件,我建议您将其签名更改为与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());
}
}
我没有意识到所使用的.Contains方法。Equals,但考虑到它,当然它必须。关于文本编写器的观点很好。虽然这是一个IRetryStore接口的实现,所以我不太担心在这里使用FileStream——它是特定于此实现的。但是我很喜欢它所提供的灵活性,特别是在测试方面……谢谢。我如何建议在单元测试中分离Save和Get方法,这样我就不会在测试另一个了?如果可能的话,我当然想把它们分开——我的测试应该独立于其他测试……看看我为Save方法提出的单元测试。没有调用Get方法。
[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
}
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>();
}