快速总结一下,如果你真的想让这个可测试,我建议:
- 将数据格式化代码提取到一个新类中(它实现了一个可以用来模拟的接口)。
- 通过这门课你的
DataSet
.
- 让新类返回
你也可以模拟
DataSet
的。IXmlSerializable
在没有看到当前代码的情况下,我必须做出一些假设(希望不要太多!) - 所以当前代码可能看起来像这样:
public class EmployeeService {
private IEmployeeRepository _Repository;
public EmployeeService(IRepository repository) {
this._Repository = repository;
}
public void ExportEmployeeData(int employeeId, string path) {
DataSet dataSet = this._Repository.Get(employeeId);
// ... Format data in the dataset here ...
dataSet.WriteXml(path);
}
}
这段代码简单有效,但不可测试(没有副作用)。此外,将所有这些逻辑放在一个地方违反了单一职责原则。
根据您的需要,这可能没问题!实现 SRP 始终只是一个目标,我们始终需要在可测试性与影响我们设计的其他因素之间取得平衡。
但是,如果您想进一步分离职责并使其可测试,您可以通过将格式化逻辑移动到它自己的类中来实现(这将实现IEmployeeDataSetFormatter
),然后将一个IEmployeeDataSetFormatter
服务的构造函数,就像IEmployeeRepository
)。格式化数据的方法将返回一个IXmlSerializable
,因此我们可以模拟它以进行安全、隔离的测试:
public interface IEmployeeDataSetFormatter {
IXmlSerializable FormatForExport(DataSet dataSet);
}
public class EmployeeDataSetFormatter: IEmployeeDataSetFormatter {
public IXmlSerializable FormatForExport(DataSet dataSet) {
// ... Format data in the dataset here ...
return (IXmlSerializable) dataSet;
}
}
public void ExportEmployeeData2(int employeeId, string path, IEmployeeDataSetFormatter formatter) {
DataSet dataSet = this._Repository.Get(employeeId);
IXmlSerializable xmlSerializable = formatter.FormatForExport(dataSet);
// This is still an intermediary step - it's probably worth
// moving this logic into its own class so you don't have to deal
// with the concrete FileStream underlying the XmlWriter here
using (XmlWriter writer = XmlWriter.Create(path)) {
xmlSerializable.WriteXml(writer);
}
}
这有一定的成本。它增加了一个额外的接口,一个额外的类,以及更多的复杂性。但它是可测试的并且更加模块化(我认为这是一种很好的方式)。