简体   繁体   English

c# - 单元测试、模拟和 ninject 工厂扩展

[英]c# - unit testing, mock and ninject factory extension

I have a console app where the user inputs a number, and I generate a feature according to that number.我有一个控制台应用程序,用户可以在其中输入一个数字,然后根据该数字生成一个功能。 I have used Ninject.Extensions.Factory for that, here are the bindings:Ninject.Extensions.Factory使用了Ninject.Extensions.Factory ,这里是绑定:

    Bind<IFeature>().To<FirstFeature>().Named("1");
    Bind<IFeature>().To<SecondFeature>().Named("2");
    Bind<IFeature>().To<ThirdFeature>().Named("3");
    Bind<IFeatureFactory>().ToFactory(() => new UseFirstArgumentAsNameInstanceProvider());

The code I want to test is:我要测试的代码是:

constructor:构造函数:

public FeatureService(IFeatureFactory featureFactory, IUILayer uiHandler, int howManyFeatures)
    {
        this.featureFactory = featureFactory;
        this.uiHandler = uiHandler;
        this.howManyFeatures = howManyFeatures;
    }

method under test:被测方法:

public async Task startService()
    {
        bool isBadInput = false;
        string userSelection = null;
        uiHandler.displayMenu(howManyFeatures);
        userSelection = uiHandler.getSelection();
        while (!userSelection.Equals((howManyFeatures+1).ToString()))
        {
            IFeature feature = null;
            try
            {
                feature = featureFactory.createFeature(userSelection);
                isBadInput = false;
            }
            catch (ActivationException ex)
            {
                uiHandler.displayErrorMessage();
                isBadInput = true;
            }
            if (!isBadInput)
            {
                await feature.execFeature();
            }
            uiHandler.displayMenu(howManyFeatures);
            userSelection = uiHandler.getSelection();
        }
    }

As you can see, when I try to createFeature , I catch the ActivationException , meaning that the user has input invalid selection (ninject fails to get the concrete class), and execFeature is not called.如您所见,当我try createFeature ,我catchActivationException ,这意味着用户输入了无效的选择(ninject 无法获取具体类),并且没有调用execFeature

I am trying to write a unit test to test that when a user inputs a valid selection, the method execFeature is called .我正在尝试编写一个单元测试来测试当用户输入有效选择时,调用execFeature方法

Here is the test:这是测试:

    [TestMethod]
    public void WhenUserEnterValidSelectionExecFeatureCalled()
    {
        //Arrange
        Mock<IFeature> featureMock = new Mock<IFeature>();
        Mock<IConsoleService> consoleServiceMock = new Mock<IConsoleService>();
        // mock user input 7
        consoleServiceMock.Setup(c => c.ReadLine()).Returns("7");
        IUILayer uiLayer = new ConsoleUILayer(consoleServiceMock.Object);
        Mock<IFeatureFactory> featureFactory = new Mock<IFeatureFactory>();
        featureMock.Setup(t => t.execFeature());
        featureFactory.Setup(t => t.createFeature(It.IsAny<string>())).Returns(featureMock.Object);
        // init FeatureService with 3 features
        IFeatureService featureService = new FeatureService(featureFactory.Object, uiLayer, 3);

        //Act
        featureService.startService();

        //Assert
        featureMock.Verify(t => t.execFeature());
    }

As you can see - I an creating a consoleMock with user input of "7" , and when I create the FeatureService I put 3 in the howManyFeatures - Test should fail (no concrete implementation).正如你所看到的-我的创建consoleMock“7”的用户输入,而当我创建FeatureService我把3howManyFeatures -测试应该失败(没有具体的实现)。

Now, when I run my program normally - if I input "7", the program acts as expected and outputs an error message.现在,当我正常运行程序时 - 如果我输入“7”,程序会按预期运行并输出错误消息。

When I run the test, every input to the consoleMock besides the HowManyFeatures + 1 passes the test ( HowManyFeatures +1 fails because it doesn't go into the while ), and it shouldn't be like that - it should fail for the number that don't have a concrete IFeature implementation (only 1, 2 and 3 have concrete implementations).当我运行测试时,除了HowManyFeatures + 1之外, HowManyFeatures + 1每个输入都通过了测试( HowManyFeatures +1失败,因为它没有进入while ),它不应该是这样 - 它应该失败的数字没有具体的IFeature实现(只有 1、2 和 3 有具体的实现)。

How do I solve this?我该如何解决这个问题? Should I "bring" the Ninject Bindings into the Tests project?我应该将Ninject Bindings “带入” Tests项目吗? should I even test this method?我什至应该测试这种方法吗? or its all useless?还是一切都没用?

Any thoughts are appreciated任何想法表示赞赏

You don't need to bring ninject binding to your test, your FeatureService does not need to know that your IFeatureFactory is based on ninject binding and it does not care about it.您不需要将 ninject 绑定带入您的测试,您的 FeatureService 不需要知道您的 IFeatureFactory 是基于 ninject 绑定,它并不关心它。
What you need to do is setup your IFeatureFacotory mock properly, now your mock returns the same IFeature no matter what is the input because this is the behavior you told it to use be doing this:您需要做的是正确设置您的 IFeatureFacotory 模拟,现在无论输入是什么,您的模拟都会返回相同的 IFeature,因为这是您告诉它使用的行为:

 featureFactory.Setup(t => t.createFeature(It.IsAny<string>())).Returns(featureMock.Object);

If you want that it will throw ActivationException when gets number larger than 3 just setup this desired behavior instead:如果您希望它在获取的数字大于 3 时抛出 ActivationException,只需设置此所需的行为即可:

featureFactory.Setup(t => t.createFeature(It.Is<string>(input => (int)input>3 ))).Throws(new ActivationException()); 

By the way you should probably mock your IUiLayer straight and inject it to the FeatureService instead of mocking your consoleService and use it in your real UiLayer implementation, it will make your testing much easier.顺便说一句,您可能应该直接模拟 IUiLayer 并将其注入到 FeatureService 而不是模拟您的 consoleService 并在您真正的 UiLayer 实现中使用它,这将使您的测试更加容易。

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

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