Как я могу справиться со слишком многими ложными ожиданиями в модульных тестах? - PullRequest
1 голос
/ 02 января 2009

Я пишу модульные тесты для своего класса представления в шаблоне MVP. Но у меня проблемы с написанием фиктивного кода установки.

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

    [Test]
    public void When_Presenter_Loads_View_Should_Display_Selected_Class_Properties()
    {
        IList<string> dataTypes =new List<string>();
        IClassGenerationView view = mockRepository.StrictMock<IClassGenerationView>();
        tableRepository = mockRepository.Stub<ITableRepository>();

        using(mockRepository.Record())
        {
            SetupResult.For(tableRepository.GetDataTypes()).Return(dataTypes);
            view.Presenter = null;
            LastCall.IgnoreArguments();
            view.DataTypes = dataTypes;
            view.Show();

            view.ClassProperties = classProperties;
            view.TableName = "Table";
            view.Table = table;
            LastCall.IgnoreArguments();
        }


        using(mockRepository.Playback())
        {
            ClassGenerationPresenter presenter = new ClassGenerationPresenter(view, clazz,  tableRepository);
            presenter.Load();
        }
    }

Есть ли запах кода в этом коде? Как я могу улучшить или упростить это?

Ответы [ 2 ]

2 голосов
/ 31 января 2012

Я боролся с этим годами. Сначала я использовал шаблон MVP, но позже переключился на модель представления (аналогично MVVM для WPF / Silverlight). Несмотря на это, результаты никогда не были удовлетворительными, особенно в Agile проектах, где пользовательский интерфейс быстро меняется. Поэтому мы больше не пишем тесты для этих типов классов и переключились на SpecFlow / WaTiN для создания автоматических тестов пользовательского интерфейса, которые все еще можно обслуживать. Подробнее об этом читайте здесь: http://www.codeproject.com/Articles/82891/BDD-using-SpecFlow-on-ASP-NET-MVC-Application

Если вы все еще хотите написать тесты для логики пользовательского интерфейса, я бы определенно не использовал метод установки для удаления некоторых вещей из вашего теста. Важно, чтобы вы могли понять причину и следствие теста, не просматривая его вверх и вниз. Вместо этого используйте более модульный тест в стиле BDD, как я объяснил в этом посте: http://www.dennisdoomen.net/2010/09/getting-more-out-of-unit-testing-in.html

В общем, я использую эти тесты в стиле BDD для классов, которые по своей природе очень характерны, и больше тестов в стиле AAA для обычных классов.

1 голос
/ 02 января 2009

После долгой бессонной ночи и исследований я нашел это решение. Когда я тщательно подумал, я придумал это. Я тестирую слишком много поведения в одном тесте. И я изменил тесты, как это

[TestFixture]
public class When_Presenter_Loads
{
    private MockRepository mockRepository;
    private ITableRepository tableRepository;
    private IClass clazz;
    private Dictionary<string, Type> properties;
    private IClassGenerationView view;
    private ClassGenerationPresenter presenter;

    [SetUp]
    public void Setup()
    {
        mockRepository =new MockRepository();
        properties = new Dictionary<string, Type>();

        clazz = mockRepository.DynamicMock<IClass>();
        view = mockRepository.DynamicMock<IClassGenerationView>();
        tableRepository = mockRepository.Stub<ITableRepository>();


    }

    [Test]
    public void View_Should_Display_Class_Properties()
    {
        using(mockRepository.Record())
        {
            SetupResult.For(clazz.Properties).Return(properties);
            view.ClassProperties = properties;
        }

        using(mockRepository.Playback())
        {
            presenter = new ClassGenerationPresenter(view, clazz, tableRepository);
            presenter.Load();
        }
    }

    [Test]
    public void View_Should_Display_Class_Name_As_A_Table_Name()
    {
        using (mockRepository.Record())
        {
            SetupResult.For(clazz.Name).Return("ClassName");
            view.TableName = "ClassName";
        }

        using (mockRepository.Playback())
        {
            presenter = new ClassGenerationPresenter(view, clazz, tableRepository);
            presenter.Load();
        }
    }

    [Test]
    public void View_Should_Display_SQL_Data_Types()
    {
        List<string> dataTypes = new List<string>();

        using(mockRepository.Record())
        {
            SetupResult.For(tableRepository.GetDataTypes()).Return(dataTypes);
            view.DataTypes = dataTypes;
        }

        using(mockRepository.Playback())
        {
            presenter = new ClassGenerationPresenter(view, clazz, tableRepository);
            presenter.Load();
        }
    }

    [Test]
    public void View_Should_Show_Table()
    {
        using (mockRepository.Record())
        {
            SetupResult.For(clazz.Name).Return("ClassName");
            view.Table = null;
            LastCall.IgnoreArguments();
        }

        using (mockRepository.Playback())
        {
            presenter = new ClassGenerationPresenter(view, clazz, tableRepository);
            presenter.Load();
        }
    }
}

Я использовал много динамического макета для проверки одного поведения за раз. Также вы можете прочитать статью Дейва One Mock Per Test об этом

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...