C # Rhino.Mocks - Как мне написать тестовый код, не повторяя себя? - PullRequest
3 голосов
/ 19 января 2011

Я хочу уничтожить все зависимости в моих модульных тестах Rhino.Mocks, но в итоге я повторяюсь. Поскольку число зависимостей продолжает увеличиваться, мне нужно пересмотреть мои существующие модульные тесты и добавить их. Это неудовлетворительно, а также сигнал о том, что я должен делать это по-другому.

Если я просто перенесу инициализацию на отдельный метод, я передам в него все макеты и ничего не добился.

Есть ли способ инициализировать, а затем передать Using (mocks.Record) в метод как лямбда-выражение? Или как ты это делаешь?!

Заранее спасибо за любые комментарии,

Андерс, Дания

    [Test, Category("UnitTest")]
    public void TestThatApplicationCanExitByDefault()
    {
        var mocks = new MockRepository();

        var workspaceViewModelProvider = mocks.StrictMock<IWorkspaceViewModelProvider>();
        var workspaceRepository = mocks.StrictMock<IWorkspaceService>();
        var userResponseProvider = mocks.StrictMock<IUserResponseProvider>();
        var versionProvider = mocks.StrictMock<IVersionProvider>();
        var eventAggregator = mocks.StrictMock<IEventAggregator>();
        var allowedLegacyImportProvider = mocks.StrictMock<IAllowedLegacyImportProvider>();
        var stateManager = mocks.StrictMock<IStateManager>();
        var currentWorkspaceChangedEvent = mocks.StrictMock<CurrentWorkspaceChangedEvent>();

        using (mocks.Record())
        {
            // constructor fires:
            eventAggregator
                .Stub(x => x.GetEvent<CurrentWorkspaceChangedEvent>())
                .Return(currentWorkspaceChangedEvent);

            currentWorkspaceChangedEvent
                .Stub(x => x.Subscribe(null))
                .IgnoreArguments();
        }

        var target = new MainWindowViewModel(
            workspaceViewModelProvider,
            workspaceRepository,
            userResponseProvider,
            versionProvider, eventAggregator, allowedLegacyImportProvider, stateManager);

        var canAppExit = target.CanAppExit();

        Assert.IsTrue(canAppExit);

        mocks.VerifyAll();
    }


    [Test, Category("UnitTest")]
    public void TestThatInsertProjectWorks()
    {
        var mocks = new MockRepository();

        var workspaceViewModelProvider = mocks.StrictMock<IWorkspaceViewModelProvider>();
        var workspaceRepository = mocks.StrictMock<IWorkspaceService>();
        var userResponseProvider = mocks.StrictMock<IUserResponseProvider>();
        var versionProvider = mocks.StrictMock<IVersionProvider>();
        var eventAggregator = mocks.StrictMock<IEventAggregator>();
        var allowedLegacyImportProvider = mocks.StrictMock<IAllowedLegacyImportProvider>();
        var stateManager = mocks.StrictMock<IStateManager>();
        var currentWorkspaceChangedEvent = mocks.StrictMock<CurrentWorkspaceChangedEvent>();
        var workspaceViewModel = mocks.StrictMock<IWorkspaceViewModel>();

        using (mocks.Record())
        {
            // constructor fires:
            eventAggregator
                .Stub(x => x.GetEvent<CurrentWorkspaceChangedEvent>())
                .Return(currentWorkspaceChangedEvent);

            currentWorkspaceChangedEvent
                .Stub(x => x.Subscribe(null))
                .IgnoreArguments();

            workspaceViewModelProvider
                .Stub(x => x.GetViewModel())
                .Return(workspaceViewModel);

            workspaceViewModel
                .Stub(x => x.InsertProject());
        }

        var target = new MainWindowViewModel(
            workspaceViewModelProvider,
            workspaceRepository,
            userResponseProvider,
            versionProvider, eventAggregator, allowedLegacyImportProvider, stateManager);

        target.InsertProject();

        mocks.VerifyAll();
    }

Ответы [ 2 ]

3 голосов
/ 19 января 2011

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

Это более очевидно на примере. Это использует Moq, но техника общая.

    private static void RunTest(Action<IThing1> test)
    {
        RunTest(test: (thing1, thing2, thing3) => test(thing1));
    }

    private static void RunTest(Action<IThing1, IThing2> test)
    {
        RunTest(test: (thing1, thing2, thing3) => test(thing1, thing2));
    }

    private static void RunTest(Action<IThing1, IThing2, IThing3> test)
    {
        IThing1 thing1 = new Mock<IThing1>().Object;
        IThing2 thing2 = new Mock<IThing2>().Object;
        IThing3 thing3 = new Mock<IThing3>().Object;

        test(thing1, thing2, thing3);
    }

    [Test]
    public void do_some_stuff_to_a_thing()
    {
        RunTest(test: thing1 => {
            //Do some testing....
        });
    }

    [Test]
    public void do_some_stuff_to_things()
    {
        RunTest(test: (thing1, thing2) => {
            //Do some testing....
        });
    }
2 голосов
/ 19 января 2011

Попробуйте использовать базовый класс с защищенными ложными объектами и используйте [SetUp] / [TestFixtureSetUp] (например, с NUnit).

Целесообразно помещать в базовый класс только общие объекты с инициализацией - используйте [SetUp] / [TestFixtureSetUp] в том же классе, где есть несколько модульных тестов, и вам нужно смоделировать / инициализировать что-то конкретное только для этих тестов.Помещение всего в вашу базу также увеличивает ваши юнит-тесты (по крайней мере, они выполняются дольше).

...