如何将样本(虚拟)数据添加到unit testing中?

在较大的项目中,我的unit testing通常需要一些“虚拟”(样本)数据来运行。 一些默认客户,用户等。我想知道你的设置是怎样的。

  1. 您如何组织/维护这些数据?
  2. 如何将其应用于您的unit testing(任何自动化工具)?
  3. 你真的需要测试数据还是认为它没用?

我目前的解决方案

我区分主数据样本数据 ,其中前者在系统投入生产时可用(第一次安装),后者是我运行测试所需的典型用例(以及在开发期间播放)。

我将所有这些存储在一个Excel文件中(因为它很容易维护),其中每个工作表包含一个特定的实体(例如用户,客户等),并标记为主文件或样本。

我有2个测试用例,我(想念)使用它来导入必要的数据:

  1. InitForDevelopment(创建架构,导入主数据,导入样本数据)
  2. InitForProduction(创建架构,导入主数据)

我使用存储库模式并拥有一个由相关unit testing实例化的虚拟存储库,它提供了一组已知数据,其中包含各种字段范围内和范围外的示例。

这意味着我可以通过从测试单元提供实例化的存储库来测试我的代码,或者在运行时提供生产存储库(通过dependency injection(Castle))。

我不知道这是一个很好的网络参考,但我从Apress出版的Steven Sanderson的Professional ASP.NET MVC 1.0书中学到了很多东西。 MVC方法自然地提供了关注点的分离,这是使测试以较少的依赖性运行所必需的。

基本元素是您的存储库实现了数据访问接口,然后由您在测试项目中构建的虚拟存储库实现相同的接口。

在我目前的项目中,我有一个界面:

namespace myProject.Abstract { public interface ISeriesRepository { IQueryable Series { get; } } } 

这是作为我的实时数据存储库(使用Linq到SQL)以及虚拟存储库实现的:

 namespace myProject.Tests.Respository { class FakeRepository : ISeriesRepository { private static IQueryable fakeSeries = new List { new Series { id = 1, name = "Series1", openingDate = new DateTime(2001,1,1) }, new Series { id = 2, name = "Series2", openingDate = new DateTime(2002,1,30), ... new Series { id = 10, name = "Series10", openingDate = new DateTime(2001,5,5) }.AsQueryable(); public IQueryable Series { get { return fakeSeries; } } } } 

然后实例化消耗数据的类,将存储库引用传递给构造函数:

 namespace myProject { public class SeriesProcessor { private ISeriesRepository seriesRepository; public void SeriesProcessor(ISeriesRepository seriesRepository) { this.seriesRepository = seriesRepository; } public IQueryable GetCurrentSeries() { return from s in seriesRepository.Series where s.openingDate.Date <= DateTime.Now.Date select s; } } } 

然后在我的测试中我可以接近它:

 namespace myProject.Tests { [TestClass] public class SeriesTests { [TestMethod] public void Meaningful_Test_Name() { // Arrange SeriesProcessor processor = new SeriesProcessor(new FakeRepository()); // Act IQueryable currentSeries = processor.GetCurrentSeries(); // Assert Assert.AreEqual(currentSeries.Count(), 10); } } } 

然后查看CastleWindsor,了解实时项目的反转控制方法,以允许生产代码通过dependency injection自动实例化您的实时存储库。 这应该让你更接近你需要的地方。

在我们公司,我们从几周和一个月开始讨论这些问题。

遵循unit testing指南:

每个测试必须是atomar并且不允许彼此相关(无数据共享),这意味着每个tust必须在开始时拥有自己的数据并在结束时清除数据。

Out产品如此复杂(5年的开发,数据库中超过100个表),几乎不可能以可接受的方式维护它。

我们尝试了数据库脚本,它在测试之前/之后创建和删除数据(有自动方法调用它)。

我会说你使用excel文件的方式很好。

我的想法让它变得更好:

  • 如果您的软件后面有一个数据库谷歌“NDBUnit”。 它是一个在unit testing数据库中插入和删除数据的框架。
  • 如果你没有数据库,那么XML在像excel这样的系统上会更灵活。

不是直接回答问题,而是限制需要使用虚拟数据的测试数量的一种方法是使用模拟框架来创建模拟对象,您可以使用这些对象伪造您在类中具有的任何依赖项的行为。

我发现使用模拟对象而不是具体的具体实现,您可以大大减少需要使用的实际数据量,因为模拟不会处理传递给它们的数据。 它们只是按照您的要求执行。

我仍然确定你可能在很多实例中需要伪数据,所以如果你已经在使用或者知道模拟框架,那么道歉。

为了清楚起见,您需要区分UNIT测试(测试模块与其他模块没有隐含的依赖关系)和应用程序测试(应用程序的测试部分)。

对于前者,您需要一个模拟框架(我只熟悉Perl,但我确信它们存在于Java / C#中)。 良好框架的标志是能够使用正在运行的应用程序,记录所有方法调用/返回,然后使用记录数据模拟所选方法(例如,您未在此特定unit testing中测试的方法)。 对于良好的unit testing,你必须模拟每个外部依赖 – 例如,没有调用文件系统,没有调用DB或其他数据访问层,除非你正在测试,等等…

对于后者,相同的模拟框架是有用的,还有创建测试数据集的能力(可以为每个测试重置)。 要为测试加载的数据可以驻留在可以加载的任何脱机存储中 – 用于Sybase DB数据的XML文件,XML,无论您喜欢什么。 我们使用BCP和XML。

请注意,如果您的整体公司框架允许 – 或者更确切地说 – “此表别名的真实数据库表名称是什么”API,那么这种“将测试数据加载到数据库”测试会非常容易。 这样,您可以使您的应用程序在测试期间查看克隆的“测试”数据库表而不是实际数据库表 – 在此类表别名API的主要目的是使数据库表从一个数据库移动到另一个数据库。