3

I have been making a little toy web application in C# along the lines of Rob Connery's Asp.net MVC storefront.

I find that I have a repository interface, call it IFooRepository, with methods, say

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

And I have three implementations of this: ISqlFooRepository, IFileFooRepostory, and IMockFooRepository.

I also have some test cases. What I would like to do, and haven't worked out how to do yet, is to run the same test cases against each of these three implementations, and have a green tick for each test pass on each interface type.

e.g.

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

I want this test method to be run three times, with some variation in the environment that allows it to get three different kinds of repository. At present I have three cut-and-pasted test classes that differ only in the implementation of the private helper method IFooRepository GetRepository(); Obviously, this is smelly.

However, I cannot just remove duplication by consolidating the cut and pasted methods, since they need to be present, public and marked as test for the test to run.

I am using the Microsoft testing framework, and would prefer to stay with it if I can. But a suggestion of how to do this in, say, MBUnit would also be of some interest.

4

5 に答える 5

3

In MbUnit, you might be able to use the RowTest attribute to specify parameters on your test.

[RowTest]
[Row(new ThisRepository())]
[Row(new ThatRepository())]
Public void GetFoo_NotNull_Test(IFooRepository repository)
{
   var results = repository.GetFoo();
   Assert.IsNotNull(results);
}
于 2008-09-17T09:07:09.603 に答える
3

テストの具体的なバージョンを含む抽象クラスと、IFooRepository を返す抽象 GetRepository メソッドを作成します。抽象クラスから派生する 3 つのクラスを作成します。各クラスは、適切な IFooRepository 実装を返す方法で GetRepository を実装します。3 つのクラスすべてをテスト スイートに追加すると、準備完了です。

一部のプロバイダーのテストを選択的に実行し、他のプロバイダーではテストを実行できないようにするには、MbUnit '[FixtureCategory]' 属性を使用してテストを分類することを検討してください。最後の 2 つは冗談です - 正直なところ!)

于 2008-09-17T09:32:03.663 に答える
1

コピーして貼り付けた 3 つのテスト メソッドがある場合は、それをリファクタリング (メソッドを抽出) して重複を取り除くことができるはずです。

つまり、これは私が念頭に置いていたものです:

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);
}
于 2008-09-17T09:16:56.400 に答える
0
[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);
}
于 2008-09-17T10:26:41.393 に答える
0

結論から言うと、次の3つの方法があります。

1) 一般的なメソッドを呼び出す 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)基本クラスを使用し、ベルガボブによる回答
このアイデアに基づいてサンプルを作成しました

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;
    }
}

これにより、2 つのテスト クラスで 4 つの合格テストが生成されます。
3 の利点は次のとおりです
。1) 余分なコードが最小で、メンテナンスが最小です
。2) 必要に応じて新しいリポジトリをプラグインするための入力が最小です。他のリポジトリとは異なり、1 つの場所で実行されます。

欠点は次のとおりです
。1) 必要に応じてプロバイダーに対してテストを実行しないという柔軟性が低い
。2) 読みにくい。

于 2008-09-17T12:22:21.850 に答える