我一直在沿着 Rob Connery 的 Asp.net MVC 店面的路线用 C# 制作一个小玩具 Web 应用程序。

我发现我有一个存储库接口,称之为 IFooRepository,带有方法,比如说

IQueryable<Foo> GetFoo();
void PersistFoo(Foo foo);

我对此有三个实现:ISqlFooRepository、IFileFooRepostory 和 IMockFooRepository。

我还有一些测试用例。我想做的(但尚未弄清楚如何做)是针对这三个实现中的每一个运行相同的测试用例,并为每个接口类型的每个测试通过打上绿色勾号。

例如

[TestMethod]
Public void GetFoo_NotNull_Test()
{
   IFooRepository repository = GetRepository();
   var results = repository. GetFoo();
   Assert.IsNotNull(results);
}

我希望这个测试方法运行三次,环境中存在一些变化,允许它获得三种不同类型的存储库。目前,我有三个剪切粘贴的测试类,它们的不同之处仅在于私有帮助器方法 IFooRepository GetRepository(); 的实现;显然,这很臭。

但是,我不能仅仅通过合并剪切和粘贴方法来删除重复,因为它们需要存在、公开并标记为测试才能运行。

我正在使用 Microsoft 测试框架,如果可以的话我更愿意继续使用它。但是,关于如何在 MBUnit 中执行此操作的建议也会引起一些兴趣。

有帮助吗?

解决方案

创建一个包含测试的具体版本的抽象类和一个返回 IFooRepository 的抽象 GetRepository 方法。创建从抽象类派生的三个类,每个类都以返回适当的 IFooRepository 实现的方式实现 GetRepository。将所有三个类添加到您的测试套件中,然后您就可以开始了。

为了能够有选择地为某些提供程序而不是其他提供程序运行测试,请考虑使用 MbUnit '[FixtureCategory]' 属性对您的测试进行分类 - 建议的类别为 '快速' '慢速' 'db' '重要' 和 '不重要' (最后两个是笑话 - 诚实!)

其他提示

在 MbUnit 中,您也许能够使用 RowTest 属性来指定测试的参数。

[RowTest]
[Row(new ThisRepository())]
[Row(new ThatRepository())]
Public void GetFoo_NotNull_Test(IFooRepository repository)
{
   var results = repository.GetFoo();
   Assert.IsNotNull(results);
}

如果您有 3 个复制和粘贴的测试方法,您应该能够重构(提取方法)它以消除重复。

IE。这就是我的想法:

private IRepository GetRepository(RepositoryType repositoryType)
{
    switch (repositoryType)
    {   
          case RepositoryType.Sql:
          // return a SQL repository
          case RepositoryType.Mock:
          // return a mock repository
          // etc
    }
}

private void TestGetFooNotNull(RepositoryType repositoryType)
{
   IFooRepository repository = GetRepository(repositoryType);
   var results = repository.GetFoo();
   Assert.IsNotNull(results);
}

[TestMethod]
public void GetFoo_NotNull_Sql()
{
   this.TestGetFooNotNull(RepositoryType.Sql);
}

[TestMethod]
public void GetFoo_NotNull_File()
{
   this.TestGetFooNotNull(RepositoryType.File);
}

[TestMethod]
public void GetFoo_NotNull_Mock()
{
   this.TestGetFooNotNull(RepositoryType.Mock);
}
[TestMethod]
public void GetFoo_NotNull_Test_ForFile()
{   
   GetFoo_NotNull(new FileRepository().GetRepository());
}

[TestMethod]
public void GetFoo_NotNull_Test_ForSql()
{   
   GetFoo_NotNull(new SqlRepository().GetRepository());
}


private void GetFoo_NotNull(IFooRepository repository)
{
  var results = repository. GetFoo();   
  Assert.IsNotNull(results);
}

总结起来,有以下三种方法:

1)使测试成为一个调用通用方法的衬垫(由 Rick 和 Hallgrim 回答)

2)使用 MBUnit 的 RowTest 功能来自动执行此操作(由 Jon Limjap 回答)。我也会在这里使用枚举,例如

[RowTest]
[Row(RepositoryType.Sql)]
[Row(RepositoryType.Mock)]
public void TestGetFooNotNull(RepositoryType repositoryType)
{
   IFooRepository repository = GetRepository(repositoryType);
   var results = repository.GetFoo();
   Assert.IsNotNull(results);
}

3)使用基类,由belugabob回答
我根据这个想法做了一个样本

public abstract class TestBase
{
    protected int foo = 0;

    [TestMethod]
    public void TestUnderTen()
    {
        Assert.IsTrue(foo < 10);
    }

    [TestMethod]
    public void TestOver2()
    {
        Assert.IsTrue(foo > 2);
    }
}

[TestClass]
public class TestA: TestBase
{
    public TestA()
    {
        foo = 4;
    }
}

[TestClass]
public class TestB: TestBase
{
    public TestB()
    {
        foo = 6;
    }
}

这会在两个测试类中产生四个通过测试。
3的优点是:
1)最少的额外代码,最少的维护
2)如果需要的话,插入新存储库的输入最少——这将在一个地方完成,与其他地方不同。

缺点是:
1)如果需要的话,不针对提供者运行测试的灵活性较低
2)更难阅读。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top