如何使用/复杂数据交互测试函数

时间:2011-06-06 19:14:29

标签: c# asp.net testing

目前,我正致力于开发相当多报告风格的系统,这些功能消耗许多不同的数据点,并将它们转换为更大的,有时是扁平化的输出。我的大多数应用程序都是基于存储库模式的变体。因此,我有一套模拟存储库,用于测试场景。我遇到的问题是这些数据点之间的交互非常复杂,很快就成为维护“模拟数据”的维护噩梦。这是一个模拟的例子:

public class SomeReportingEntity
{
private IProductRepo ProductRepo;
private IManagerRepo ManagerRepo;
private ILocationRepo LocationRepo;
private IOrdersService OrdersService;
private IEmployeeRepo EmployeeRepo;

public ReportingEntity(IProductRepo ipr, IManagerRepo imr, ILocationRepo ilr, IOrdersService ios, 
    IEmployeeRepo ier){
        //Load these to private vars...
}

    //This is the function that I want to test...
public SomeReportingEntity GetManagerSalesByRegionReport()
{
    //Make a complex join on all sub collections.  These
    //sub collections are all under test individually.
    var MangerSalesByRegionItems = From x in ProductRepo.CurrentProducts()
                              Join y in OrdersService.FutureOrders() On ...
                              Join z in EmployeeRepo.ActiveEmployees() On  ...
                              Join a in LocationRepo.GetAllRegions() On ...
                              Join b In ManagerRepo.GetActiveManagers On ...
                              Select new SomeReportingEntity() With { ... }

    return MangerSalesByRegionItems.ToList();       
}

}

不可否认,这是一个非常人为的例子,但我想强调的基本思想是我有几个我正在加入的存储库,我需要创建许多测试来确保这个复杂的查询按预期进行。由于连接操作非常复杂,它使得模拟数据非常难以保持一致 - 特别是因为我必须添加更多关联并测试其他点。此外,我需要能够在模拟中输入特定的记录状态(例如缺少分配的经理的员工)来验证查询是否正确处理这些情况。

所以这是我的问题:

  1. “嘲笑”这些数据的最佳方式是什么,这样才不会成为一场噩梦般的噩梦?我有很多人建议构建一个内存数据库来支持这个。
  2. 我真的在这里遇到架构问题吗?在报告方案中,我发现自己处于这种模式中,我将许多不相关的数据点合并到一个新的混合实体中。随着Linq的出现,这很容易做到并且意图清晰度很高,但有时感觉我有点作弊。

3 个答案:

答案 0 :(得分:1)

我自己一直致力于数据量大的项目。对我们有用的是使用Repository本身来水合对象,然后将它们序列化为XML。我们将XML文件放入我们的测试项目中,并将其作为自动化测试的起点。这很好,因为它可以确保您的模拟数据看起来像真实的数据。

我们的测试看起来像这样...

var object1 = XmlUtil.LoadObject1("filename1");
var object2 = XmlUtil.LoadObject2("filename2");

var result = SomeConverter.Convert(object1, object2);

Assert("somevalue", result.Property1);

如果您需要进行内联查找,可以添加一个模拟存储库,该存储库将提供相同级别的依赖注入。

此方法的缺点是数据架构是否发生变化。有时,如果数据模式已更改,则测试可能会过时。如果您的架构仍然存在很大的变化,我会保持您的自动化测试很小,直到架构稳定下来。专注于单元测试,直到您知道模式相对稳定。

答案 1 :(得分:1)

您要做的第一件事是制作集中对象,知道如何检索不同存储库的数据。由于这只是报告,因此您更容易,因为您不必担心更改跟踪。

从后勤角度来看,我要考虑的一件事是建立一个本地数据库来保存远程数据(使用代理定期更新)。这将消除一些调用远程服务和动态聚合数据的问题。您还可以在开始时预处理一些数据。

当我使用存储库模式时,我将其与Unit Of Work pattern结合使用。工作单位是为你做所有腿部工作的人。从理论上讲,您的UoW可以从多个服务中引入数据,并根据配置将其呈现给存储库。

为了进行测试,您可以使用InMemoryUnitOfWork在一个地方提供所有数据。

答案 2 :(得分:-1)

您必须准确决定要测试的内容。

这样做的一种方法可能是假装你正在使用TDD。假设您的GetManagerSalesByRegionReport方法不存在(或实际删除它)。你必须:

  1. 编写失败的单元测试。它最简单的测试方法是:你可以调用方法,并且当数据没有任何问题时它不会抛出异常。
  2. 您需要创建方法,为空。它应返回void,因为您的测试不需要它返回任何内容。
  3. 你的考试现在应该通过。
  4. 添加测试以确保返回相应类型的List,即使所有子存储库都没有数据。
  5. 您必须更改方法以返回列表类型,并且您必须将其更改为返回null。您的测试仍然会失败,因此将其更改为返回空的List并且它将通过。
  6. 还剩下什么?这些是INNER连接,因此除非所有存储库至少包含一行,否则您将不会获得任何数据。因此,测试一下:创建一个测试,其中每个repo包含一行,并确保返回的列表包含适当的行数。然后,测试每个返回行的相应属性。然后测试如果任何repos不包含任何行,则不返回任何数据。

    然后,如果一些回购包含多行,可能会测试会发生什么。

    然后,我不知道还有什么可以测试。