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

时间:2016-05-04 11:42:37

标签: c# unit-testing mocking ninject ninject-extensions

我有一个控制台应用程序,用户输入一个数字,我根据该数字生成一个功能。我使用了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());

我要测试的代码是:

构造

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

测试方法:

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

正如您所看到的,当我trycreateFeature时,我catch ActivationException,意味着用户输入了无效选项(ninject无法获得具体内容) (),并且execFeature没有被调用。

我正在尝试编写一个单元测试来测试当用户输入有效选择时,方法execFeature被称为

以下是测试:

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

正如您所见 - 我创建的consoleMock用户输入为&#34; 7&#34; , 当我创建FeatureService时,我将{strong> 3 放在howManyFeatures - 测试失败(没有具体实施)。

现在,当我正常运行我的程序时 - 如果我输入&#34; 7&#34;,程序按预期运行并输出错误信息。

当我运行测试时,除了HowManyFeatures + 1之外,每个对consoleMock的输入都通过了测试(HowManyFeatures +1失败,因为它没有进入while),它不应该是这样的 - 对于没有具体IFeature实现的数字(仅有1,2和3具有具体实现),它应该失败。

我该如何解决这个问题?我应该带#34;进入Ninject Bindings项目的Tests?我应该测试这种方法吗?还是一切都没用?

感谢任何想法

1 个答案:

答案 0 :(得分:1)

您不需要将ninject绑定带到您的测试中,您的FeatureService不需要知道您的IFeatureFactory基于ninject绑定而且它不关心它。
您需要做的是正确设置您的IFeatureFacotory模拟,现在您的模拟返回相同的IFeature,无论输入是什么,因为这是您告诉它使用的行为:

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

如果你想要,当数字大于3时它将抛出ActivationException,只需设置这个所需的行为:

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

顺便说一句,您应该直接模拟您的IUiLayer并将其注入FeatureService,而不是模拟您的consoleService并在真实的UiLayer实现中使用它,它将使您的测试更容易。