Наследование модульного тестирования

У меня есть вопрос относительно модульного тестирования. Допустим, у меня есть несколько классов, которые наследуют поведение от родительского класса. Я не хочу проверять все детские классы на такое поведение. Вместо этого я бы проверил родительский класс. Однако я должен также предоставить тест, доказывающий, что поведение доступно в детских классах. Вы думаете, что-то вроде Assert.IsTrue (new ChildClass () is ParentClass) имеет смысл?

7 ответов


Если вы используете современную систему модульного тестирования, я не понимаю заявление

Я не хочу тестировать все дочерние классы для этого поведения.

ваши модульные тесты (написанные против экземпляра родительского класса) должны работать без изменений, если вы передаете им экземпляр дочернего класса,предоставил что ваш дочерний класс не переопределил какой-либо аспект поведения родителя таким образом, чтобы нарушить контракт на унаследованные методы. И это именно то, что вам нужно проверить, не так ли?

Если вас беспокоит время, необходимое для запуска тестов, я бы дважды проверил, чтобы убедиться, что ваши тесты разделены таким образом, что вы можете выборочно запускать тесты на основе того, над чем вы активно работаете (но все равно периодически запускать полный портфель, чтобы поймать непреднамеренные зависимости.)


Я думаю, что написание теста, который работает наследование, является пустой тратой времени. Компилятор проверит, что методы базового класса доступны, если вы попытаетесь их использовать, предполагая, что вы не поймаете intellisense. Вероятно, я бы проверил поведение в одном дочернем классе, а затем только в каждом дочернем классе, который изменяет поведение (или какое-то состояние, от которого зависит поведение).


сделайте ваши тесты наследуемыми от теста базового класса, что-то [очень]примерно так.

public class MyBaseClass
{
    public virtual void DoStuff() { }
    public virtual void DoOtherStuff() { }
}

public class MySubClass : MyBaseClass
{
    public override void DoOtherStuff()
    {
        // different to to base
    }
}

public abstract class TestOfBaseClass
{
    protected abstract MyBaseClass classUnderTest { get; }

    [TestMethod]
    public void TestDoStuff()
    {
        classUnderTest.DoStuff();
        Assert.StuffWasDone();
    }
}

[TestClass]
public class WhenSubclassDoesStuff : TestOfBaseClass
{
    protected override MyBaseClass classUnderTest
    {
        get { return new MySubClass(); }
    }

    [TestMethod]
    public void ShoudDoOtherStuff()
    {
        classUnderTest.DoOtherStuff();
        Assert.OtherStuffDone();
    }
}

большинство популярных тестовых фреймворков будут запускать метод теста в базовом тесте при выполнении тестов подкласса.

или, может быть, посмотрите на что-то вроде https://github.com/gregoryyoung/grensesnitt


вы не хотели бы тестировать тип объекта,если он выходит из нетипизированного Заводского метода. В противном случае вы пишете модульный тест против компилятора C#, который не является тем, что вы хотите сделать.


компилятор C# позаботится о такой проверке для вас.

Если вам нравится, вы можете написать что-то вроде:

ParentClass childClass = new ChildClass()
var testOutput = childClass.ParentMethod();
Assert.IsNotNull(testOutput);

есть два подхода, которые можно использовать для тестирования поведение базового класса:

  1. создайте реализацию заглушки базового класса и модульный тест заглушки. Тестируйте только общедоступные методы. Бессмысленно тестировать ваши частные и защищенные методы, так как они будут потребляться общедоступными методами, которые вы должны протестировать в своих подклассах. Этот подход не будет обеспечивать, чтобы ваши реализации базового класса не затеняли поведение неправильно.
  2. создайте тестовый суперкласс для модульных тестов, который выполняет методы базового класса. Всякий раз, когда вы тестируете подкласс базового класса, ваш тестовый класс наследовать от суперкласса теста. Этот подход гарантирует, что вы не изменили поведение базового класса непреднамеренно, но ограничивает гибкость вашего теста.

Не трудитесь проверять, что наследование действительно работает (все Assert.IsTrue(new ChildClass() is ParentClass) вещь). Вы должны только проверить поведение. Это структурная особенность .Net framework (наследование), и вы должны верить, что она работает, иначе вы окажетесь в нисходящей спирали проверки функций платформы.


Я считаю, что ваша тестовая структура должна отражать структуру объекта поэтому, если у вас есть класс автомобиля, который наследует от класса автомобиля

тогда у вас должен быть класс TestCar, который наследуется от класса TestVehicle

при выполнении этого теста автомобиль автоматически наследует правильные тесты для всех тестов транспортного средства это означает, что если функция переопределена в автомобиле, она, скорее всего, сломает тест, выделив, что переопределенный тест требуется в автомобиле для поддержки нового поведение, если тест не сломан, то переопределение, вероятно, было излишним в первую очередь

например

class Vehicle
{
    public virtual bool LicenceRequired
    {
        get{throw new NotImplmentedException()
    }
}
class Bicycle:Vehicle
{
    public override bool LicenceRequired
    {
        get{return false;}
    }
}
class Car:Vehicle
{
    public override bool LicenceRequired
    {
        get{return true;}
    }
}
class TestVehicle
{
    public virtual Void LicenceRequiredTest()
    {
        Try
        {
            LicenceRequired
            Assert.Fail();
        }
        Catch(){}
    }
}
class TestBicycle:TestVehicle
{
    public override void LicenceRequiredTest()
    {
        Assert.IsFalse(LicenceRequired);
    }
}
class TestCar:TestVehicle
{
    public override void LicenceRequiredTest()
    {
        Assert.IsTrue(LicenceRequired);
    }
}

Примечание: наследование должно использоваться только при тестировании в наследство объекты, не только потому, что вы хотите сделать тот же тест на 10 несвязанных объектов. если вы хотите это сделать, я бы предложил статический вспомогательный класс