c#-单元测试、模拟和ninject工厂扩展
我有一个控制台应用程序,用户在其中输入一个数字,我根据该数字生成一个功能。为此,我使用了c#-单元测试、模拟和ninject工厂扩展,c#,unit-testing,mocking,ninject,ninject-extensions,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<ThirdFeatu
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();
}
}
[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());
}
如您所见,当我尝试创建功能时,我捕获激活异常
,这意味着用户输入了无效的选择(ninject无法获得具体的类),并且未调用execFeature
我试图编写一个单元测试来测试当用户输入一个有效的选择时,方法execFeature
被称为
下面是测试:
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();
}
}
[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());
}
[TestMethod]
当UserIntervalidSelectionExecFeatureCalled()时公共无效
{
//安排
Mock featureMock=新建Mock();
模拟控制台服务模拟=新建模拟();
//模拟用户输入7
consoleServiceMock.Setup(c=>c.ReadLine())。返回(“7”);
IUILayer uiLayer=新的ConsoleUILayer(consoleServiceMock.Object);
Mock featureFactory=new Mock();
featureMock.Setup(t=>t.execFeature());
Setup(t=>t.createFeature(It.IsAny()).Returns(featureMock.Object);
//init FeatureService具有3个功能
IFeatureService featureService=新的featureService(featureFactory.Object,uiLayer,3);
//表演
featureService.startService();
//断言
验证(t=>t.execFeature());
}
如您所见-我正在创建一个控制台,用户输入为“7”,
当我创建FeatureService
时,我将3放在howManyFeatures
-测试应该失败的地方(没有具体的实现)
现在,当我正常运行我的程序时——如果我输入“7”,程序将按预期运行并输出错误消息
当我运行测试时,除了HowManyFeatures+1
之外,控制台的每个输入都通过了测试(HowManyFeatures+1
失败,因为它没有进入while
),它不应该是这样的-它应该失败,因为没有具体的IFeature
实现(只有1、2和3有具体的实现)
我该如何解决这个问题?我应该将Ninject绑定
引入Tests
项目吗?我甚至应该测试这个方法吗?还是说它完全没有用
您不需要将ninject绑定带到您的测试中,您的FeatureService不需要知道IFeatureFactory基于ninject绑定,它也不关心它。
您需要做的是正确设置iFeatureFactory模拟,现在,无论输入是什么,模拟都会返回相同的IFeature,因为这是您告诉它要使用的行为:
featureFactory.Setup(t => t.createFeature(It.IsAny<string>())).Returns(featureMock.Object);
featureFactory.Setup(t=>t.createFeature(It.IsAny()).Returns(featureMock.Object);
如果您希望它在获取大于3的数字时抛出ActivationException,只需设置此所需行为即可:
featureFactory.Setup(t => t.createFeature(It.Is<string>(input => (int)input>3 ))).Throws(new ActivationException());
featureFactory.Setup(t=>t.createFeature(It.Is(input=>(int)input>3)).Throws(new ActivationException());
顺便说一句,您可能应该直接模拟iUI层并将其注入FeatureService,而不是模拟consoleService并在真正的UiLayer实现中使用它,这将使您的测试更加容易