Создайте полный TestSuite для интерфейса или реализации. - PullRequest
1 голос
/ 18 октября 2019

Мне было интересно узнать, как лучше писать тесты, если у меня несколько реализаций на интерфейс. Должен ли я реплицировать каждый тест для каждой реализации или я могу создать абстрактный класс, содержащий все тесты об интерфейсе, а затем создать простой класс теста для реализации, который расширяет мой абстрактный класс теста?

Я следую «Искусству модульного тестирования», написанному Ошеровым, и он всегда повторяет, что мы должны держать тесты и наборы тестов настолько простыми, насколько мы можем, поэтому я не знаю, добавляю ли я рефератКласс увеличит сложность тестов на чтение другими разработчиками.

Какой из следующих примеров является общепринятым и более читабельным?

Пример кода:

public interface IMyInterface() 
{
    public string MyMethod(string input);
}

public class MyClassA : IMyInterface 
{
    public string MyMethod(string input) 
    {
        return input;
    }
} 

public class MyClassB : IMyInterface 
{
    public string MyMethod(string input) 
    {
        return "hello from MyClassB";
    }
}

public class MyClassC : IMyInterface 
{
    public string MyMethod(string input) 
    {
        throw new NotImplementedException();
    }
}

TestSuite1:

[TestFixture]
public class MyClassATest {

    [Test]
    public void MyMethod_WhenCalled_ReturnsANotNullString() 
    {
        //arrange
        MyClassA sut = new MyClassA();

        //act
        string result = sut.MyMethod("hi");

        //assert
        Assert.IsNotNull(result);
    }
} 

[TestFixture]
public MyClassBTest {

    [Test]
    public void MyMethod_WhenCalled_ReturnsANotNullString() 
    {
        //arrange
        MyClassA sut = new MyClassB();

        //act
        string result = sut.MyMethod("hi");

        //assert
        Assert.IsNotNull(result);
    }
}

[TestFixture]
public MyClassCTest {

    [Test]
    public void MyMethod_WhenCalled_ReturnsANotNullString() 
    {
        //arrange
        MyClassA sut = new MyClassC();

        //act
        string result = sut.MyMethod("hi");

        //assert
        Assert.IsNotNull(result);
    }
}

TestSuite 2:

[TestFixture]
public abstract class IMyInterfaceTest<TImplementation> where TImplementation : IMyInterface {

    [Test]
    public void MyMethod_WhenCalled_ReturnsANotNullString() 
    {
        //arrange
        TImplementation sut = new MyClassC();

        //act
        string result = sut.MyMethod("hi");

        //assert
        Assert.IsNotNull(result);
    }
}

[TestFixure]
public class MyClassATest : IMyInterfaceTest<MyClassA> {}
[TestFixure]
public class MyClassATest : IMyInterfaceTest<MyClassB> {}
[TestFixure]
public class MyClassATest : IMyInterfaceTest<MyClassC> {}

1 Ответ

1 голос
/ 18 октября 2019

Почему бы не попробовать этот подход, используя TestCaseSource (https://github.com/nunit/docs/wiki/TestCaseData). Преимущество в том, что у вас есть один тест вместо множества повторяющихся тестов, которые делают то же самое.

        [TestCaseSource(typeof(MyDataClass), "TestCases")]
        public void MyMethod_WhenCalled_ReturnsANotNullString(IMyInterface sut, string value)
    {
        //arrange

        //act
        string result = sut.MyMethod(value);

        //assert
        Assert.IsNotNull(result);
    }

    public class MyDataClass
    {
        public static IEnumerable TestCases
        {
            get
            {
                yield return new TestCaseData(new MyClassA(), "hi");
                yield return new TestCaseData(new MyClassB(), "test");
                yield return new TestCaseData(new MyClassC(), "another");
            }
        }
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...