由于我对单元测试和 TDD 有点陌生,所以这篇文章更多地是一个讨论的开始。
我目前正在为与多个数据库交互的 .NET 进程编写一些单元测试,并且正在使用模拟数据库上下文来尝试覆盖我的测试中的不同边缘情况,验证程序本身中的异常处理等等。话虽如此,我的一些单元测试使用有效数据,而另一些则没有。
在将有效/虚假数据添加到模拟数据库上下文时,我正在寻找建议的最佳实践方面的反馈。我见过人们以多种方式做到这一点(例如 - 实现存储库模式,将模拟数据添加到 .csv 文件并使它们成为项目的一部分,等等......)。
我目前正在考虑使用存储库模式将Survey
对象添加到Surveys
目标数据库中的表中。
首先,我有界面:
public interface ISurveyRepository
{
IQueryable<Survey> SurveySeries { get; }
}
这在单元测试所需的模拟假/有效数据存储库中都实现了
class FakeSurveyRepository : ISurveyRepository
{
private static IQueryable<Survey> fakeSurveySeries = new List<Survey> {
new Survey { id = 1, SurveyName="NotValid1", SurveyData="<data>fake</data>"},
new Survey { id = 2, SurveyName="NotValid2", SurveyData="<data>super fake</data>"},
.........,
new Survey {id = 10, SurveyName="NotValid10", SurveyData="<data>the fakest</data>" }
}.AsQueryable();
public IQueryable<Survey> SurveySeries
{
get { return fakeSurveySeries; }
}
}
// RealSurveyRepository : ISurveyRepository is similar to this, but with "good" data
然后,我有一个类通过在构造函数中传递对系列的引用来使用这些数据来获取虚假/有效数据:
public class SurveySeriesProcessor
{
private ISurveyRepository surveyRepository;
public SurveySeriesProcessor( ISurveyRepository surveyRepository )
{
this.surveyRepository = surveyRepository;
}
public IQueryable<Survey> GetSurveys()
{
return surveyRepository.SurveySeries
}
}
然后可以在我的测试中使用这些对象,例如:
[TestClass]
public class SurveyTests
{
[TestMethod]
WhenInvalidSurveysFound_SurveyCopierThrowsInvalidSurveyDataErrorForEach()
{
// create mocking DB context and add fake data
var contextFactory = new ContextFactory( ContextType.Mocking );
var surveySeriesProcessor = new SurveySeriesProcessor( new FakeSurveyRepository() );
foreach(Survey surveyRecord in surveySeriesProcessor.GetSurveys() )
{
contextFactory.TargetDBContext.Surveys.AddObject( surveyRecord );
}
// instantiate object being tested and run it against fake test data
var testSurveyCopier = new SurveyCopier( contextFactory );
testSurveyCopier.Start();
// test behavior
List<ErrorMessage> errors = testSurveyCopier.ErrorMessages;
errors.Count.ShouldEqual( surveySeriesProcessor.GetSurveys().Count );
foreach(ErrorMessage errMsg in errors)
{
errMsg.ErrorCode.ShouldEqual(ErrorMessage.ErrorMessageCode.InvalidSurveyData);
}
}
}
注意:我意识到在提供的示例代码中,我不一定需要使实现的类ISurveyRepository
将系列返回为IQueryable<Survey>
(它们很可能是List<Survey>
)。但是,我将在未来扩展接口和这些类的功能,以根据添加到 LINQ 查询的某些标准过滤掉假/有效系列,这就是我让存储库实现的原因IQueryable<>
。这是模拟代码,旨在传达我所想的基本原则。
考虑到所有这些,我要问的是:
- 您对我在这种情况下可以采取的替代方法有什么建议吗?
- 您过去采用了哪些方法,您喜欢/不喜欢它们的哪些方面?您发现哪个最容易维护?
- 鉴于我发布的内容,您是否注意到我的一般单元测试方法存在缺陷?有时我觉得我编写的单元测试试图涵盖太多内容,而不是简洁、优雅和中肯。
这意味着有点开放的讨论。请记住,这是我写过的第一组单元测试(不过,我已经阅读了大量关于该主题的文献)。