0

I have a few methods that are used from different class tests. Also, some other common methods are used for preparing the test data.

What is the common practice to handle this in tests? Should I handle this like any other case by having either base class or some static class (e.g. Utils.CommonMethod())? I use static class, since I don't really like the base class in this situation as it will imply that ClassTest1 and ClassTestN are interchangeable.

[TestClass]
public class ClassTest1
{
   [TestMethod]
   [DynamicData...]
   public void Method(TestData data)
   {
       ...
       CommonMethod1();
   }

   public static IEnumerable<object[]> GetTestData()
   {
      CommonMethod2();
      ...
   }
}

[TestClass]
public class ClassTestN
{
   [TestMethod]
   [DynamicData...]
   public void Method(TestData data)
   {
       ...
       CommonMethod1();
   }

   public static IEnumerable<object[]> GetTestData()
   {
      CommonMethod2();
      ...
   }
}
2
  • "it will imply that ClassTest1 and ClassTestN are interchangeable." I can only think you are misunderstanding the LSP here; two classes deriving from the same base class does not mean they are (fully) interchangeable, only that they are interchangeable when implementing the functionality in the base class. Oct 29, 2022 at 21:01
  • Can't you use both? Personally I used base methods when they need to access the data in the test class itself, and I use static methods for pure functions that take all their inputs as arguments. Both have their place.
    – John Wu
    Oct 30, 2022 at 17:47

1 Answer 1

3

Using inheritance to reuse functionality can lead to the following problem (in languages, like C#, that do not support multiple inheritance).

Let test classes A and B use some common functionality AB. Let test classes B and C use some other common functionality BC.
When we use base classes to access this functionality, B should derive from both AB and BC. C# does not support this.

Therefore, my advise would be to move the common functionality to separate classes whenever possible.
(This fits with the "composition over inheritance"-principle.)

For the specific case of DynamicDataAttribute and GetTestData() you can abstract this data into a class of its own: a custom data source attribute (derive from System.Attribute and implement ITestDataSource). Meziantou's blog gives an example implementation and how to attach the attribute to the test method:

public class MyCustomDataSourceAttribute: Attribute, ITestDataSource
{
    public static IEnumerable<object[]> GetTestData(MethodInfo testMethod)
    {
        yield return new object[] { new TestData(1) };
        yield return new object[] { new TestData(2) };
        yield return new object[] { new TestData(3) };
    }

    public string GetDisplayName(MethodInfo methodInfo, object[] data)
    {
        if (data != null && data.Count == 1 && data data[0] is TestData testData)
        {
            return $"Custom - {methodInfo.Name}, {testData});
        }
        else
        {
            return null;
        }
    }
}

and

[TestClass]
public class ClassTest1
{
   [TestMethod]
   [MyCustomDataSource]
   public void Method(TestData data)
   {
       ...
       CommonMethod1();
   }
}
1
  • 2
    This. Take advantage of all the mechanisms and features of your programming language or framework for tests. Of course, under the hood, [MyCustomDataSource] might or might not depends on utilities written as static methods or be part of a hierarchy of classes. But first goes first. The key here is what is reading the developer when it opens ClassTest1. The cleaner and more comprehensive the code the better. Calls to static or inherited methods are technical details unrelated to the test.
    – Laiv
    Oct 31, 2022 at 9:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.