简体   繁体   English

如何在单元测试中处理太多的模拟期望?

[英]How can I deal with too Many Mock Expectations in unit tests?

I am writing unit tests for my presentation class in MVP pattern.But I am having trouble to write mock setup code. 我正在以MVP模式为演示文稿类编写单元测试,但是我无法编写模拟设置代码。

I have a presenter and when presenter's Load method called I want to test view should load class properties, table fields, data types,set presenter.... So When I have a different thing to do when presenter load always I have to add new expectation to test. 我有一个演示者,当调用演示者的Load方法时,我想测试视图应加载类属性,表字段,数据类型,设置演示者...。因此,当演示者加载时我要执行其他操作时,总是必须添加新的期望测试。 And test is getting bigger every time. 每次测试都会变得越来越大。

    [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();
        }
    }

Is there a code smell in this code? 该代码中是否有代码气味? How Can I improve or simplify this? 我该如何改善或简化?

I've struggled with this for years. 我为此一直苦苦挣扎。 At first I used the MVP pattern, but switched to the Presentation Model (similar to MVVM for WPF/Silverlight) later on. 最初,我使用MVP模式,但后来切换到Presentation Model(类似于WPF / Silverlight的MVVM)。 Regardless, the results were never satisfactory, especially in Agile projects where the UI changes rapidly. 无论如何,结果永远不会令人满意,尤其是在UI快速变化的敏捷项目中。 Therefor, we don't write tests for those types of classes anymore, and have switched to SpecFlow/WaTiN to create automated UI tests that are still maintainable. 因此,我们不再为这些类型的类编写测试,而是切换到SpecFlow / WaTiN来创建仍可维护的自动UI测试。 Read more about that here: http://www.codeproject.com/Articles/82891/BDD-using-SpecFlow-on-ASP-NET-MVC-Application 在此处阅读有关此内容的更多信息: http : //www.codeproject.com/Articles/82891/BDD-using-SpecFlow-on-ASP-NET-MVC-Application

If you still want to write tests for the UI logic, I would most definitely not use a setup method to remove some of the stuff from your test. 如果您仍然想为UI逻辑编写测试,那么我绝对不会使用设置方法从测试中删除某些内容。 It's essential that you are be able to understand the cause and effect of a test without the need to browse up and down. 必须能够理解测试的因果关系而无需上下浏览。 Instead, use a more BDD-style unit test like I've explained in this blog post: http://www.dennisdoomen.net/2010/09/getting-more-out-of-unit-testing-in.html 相反,请使用更加BDD风格的单元测试,如我在此博客文章中所解释的: http : //www.dennisdoomen.net/2010/09/getting-more-out-of-unit-testing-in.html

In general, I use these BDD-style tests for classes that are very orchastrational by nature, and more AAA-style tests for ordinary classes. 通常,我将这些BDD风格的测试用于本质上非常协调的类,而将更多AAA风格的测试用于普通类。

After a long sleepless night and research I have found this solution.When I thougt carefully I have came up with this. 经过漫长的不眠之夜和研究,我找到了这个解决方案。当我仔细地思考时,我想到了这个解决方案。 I am testing too many behaviour in one test. 我在一项测试中测试了太多的行为。 And I have changed the tests like this 我已经改变了这样的测试

[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();
        }
    }
}

I have used lots of Dynamic mock to test one behaviour at time. 我使用了许多动态模拟程序来一次测试一种行为。 Also you can read Dave's One Mock Per Test article about this 您也可以阅读Dave的“每个测试一个模拟”文章

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM