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

<p>I find that I have a repository interface, call it IFooRepository, with methods, say</p>

<pre><code>IQueryable&lt;Foo&gt; GetFoo();
void PersistFoo(Foo foo);
</code></pre>

<p>And I have three implementations of this: ISqlFooRepository, IFileFooRepostory, and IMockFooRepository.</p>

<p>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.</p>

<p>e.g.</p>

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

<p>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.</p>

<p>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.</p>

<p>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.</p>

[{'answer_id': 81326, 'author': 'Jon Limjap', 'author_id': 372, 'author_profile': 'https://Stackoverflow.com/users/372', 'pm_score': 2, 'selected': False, 'text': '<p>In MbUnit, you might be able to use the RowTest attribute to specify parameters on your test.</p>\n\n<pre><code>[RowTest]\n[Row(new ThisRepository())]\n[Row(new ThatRepository())]\nPublic void GetFoo_NotNull_Test(IFooRepository repository)\n{\n   var results = repository.GetFoo();\n   Assert.IsNotNull(results);\n}\n</code></pre>\n'}, {'answer_id': 81395, 'author': 'RickL', 'author_id': 7261, 'author_profile': 'https://Stackoverflow.com/users/7261', 'pm_score': 1, 'selected': False, 'text': '<p>If you have your 3 copy and pasted test methods, you should be able to refactor (extract method) it to get rid of the duplication.</p>\n\n<p>i.e. this is what I had in mind:</p>\n\n<pre><code>private IRepository GetRepository(RepositoryType repositoryType)\n{\n    switch (repositoryType)\n    {   \n          case RepositoryType.Sql:\n          // return a SQL repository\n          case RepositoryType.Mock:\n          // return a mock repository\n          // etc\n    }\n}\n\nprivate void TestGetFooNotNull(RepositoryType repositoryType)\n{\n   IFooRepository repository = GetRepository(repositoryType);\n   var results = repository.GetFoo();\n   Assert.IsNotNull(results);\n}\n\n[TestMethod]\npublic void GetFoo_NotNull_Sql()\n{\n   this.TestGetFooNotNull(RepositoryType.Sql);\n}\n\n[TestMethod]\npublic void GetFoo_NotNull_File()\n{\n   this.TestGetFooNotNull(RepositoryType.File);\n}\n\n[TestMethod]\npublic void GetFoo_NotNull_Mock()\n{\n   this.TestGetFooNotNull(RepositoryType.Mock);\n}\n</code></pre>\n'}, {'answer_id': 81475, 'author': 'belugabob', 'author_id': 13397, 'author_profile': 'https://Stackoverflow.com/users/13397', 'pm_score': 3, 'selected': True, 'text': "<p>Create an abstract class that contains concrete versions of the tests and an abstract GetRepository method which returns IFooRepository.\nCreate three classes that derive from the abstract class, each of which implements GetRepository in a way that returns the appropriate IFooRepository implementation.\nAdd all three classes to your test suite, and you're ready to go.</p>\n\n<p>To be able to selectively run the tests for some providers and not others, consider using the MbUnit '[FixtureCategory]' attribute to categorise your tests - suggested categories are 'quick' 'slow' 'db' 'important' and 'unimportant' (The last two are jokes - honest!)</p>\n"}, {'answer_id': 81810, 'author': 'Hallgrim', 'author_id': 15454, 'author_profile': 'https://Stackoverflow.com/users/15454', 'pm_score': 0, 'selected': False, 'text': '<pre><code>[TestMethod]\npublic void GetFoo_NotNull_Test_ForFile()\n{   \n   GetFoo_NotNull(new FileRepository().GetRepository());\n}\n\n[TestMethod]\npublic void GetFoo_NotNull_Test_ForSql()\n{   \n   GetFoo_NotNull(new SqlRepository().GetRepository());\n}\n\n\nprivate void GetFoo_NotNull(IFooRepository repository)\n{\n  var results = repository. GetFoo();   \n  Assert.IsNotNull(results);\n}\n</code></pre>\n'}, {'answer_id': 82513, 'author': 'Anthony', 'author_id': 5599, 'author_profile': 'https://Stackoverflow.com/users/5599', 'pm_score': 0, 'selected': False, 'text': "<p>To Sum up, there are three ways to go:</p>\n\n<p>1) Make the tests one liners that call down to common methods (answer by Rick, also Hallgrim)</p>\n\n<p>2) Use MBUnit's RowTest feature to automate this (answer by Jon Limjap). I would also use an enum here, e.g.</p>\n\n<pre><code>[RowTest]\n[Row(RepositoryType.Sql)]\n[Row(RepositoryType.Mock)]\npublic void TestGetFooNotNull(RepositoryType repositoryType)\n{\n   IFooRepository repository = GetRepository(repositoryType);\n   var results = repository.GetFoo();\n   Assert.IsNotNull(results);\n}\n</code></pre>\n\n<p>3) Use a base class, answer by belugabob<br>\nI have made a sample based on this idea</p>\n\n<pre><code>public abstract class TestBase\n{\n    protected int foo = 0;\n\n    [TestMethod]\n    public void TestUnderTen()\n    {\n        Assert.IsTrue(foo &lt; 10);\n    }\n\n    [TestMethod]\n    public void TestOver2()\n    {\n        Assert.IsTrue(foo &gt; 2);\n    }\n}\n\n[TestClass]\npublic class TestA: TestBase\n{\n    public TestA()\n    {\n        foo = 4;\n    }\n}\n\n[TestClass]\npublic class TestB: TestBase\n{\n    public TestB()\n    {\n        foo = 6;\n    }\n}\n</code></pre>\n\n<p>This produces four passing tests in two test classes.<br>\nUpsides of 3 are:<br>\n1)  Least extra code, least maintenance <br>\n2)  Least typing to plug in a new repository if need be - it would be done in one place, unlike the others.</p>\n\n<p>Downsides are:<br>\n1)  Less flexibility to not run a test against a provider if need be<br>\n2)  Harder to read.<br></p>\n"}]
['https://Stackoverflow.com/questions/81317', 'https://Stackoverflow.com', 'https://Stackoverflow.com/users/5599/']