1

我的 Presenter 中有一个方法,它创建一个包含所有用户输入的类,称为UserInputEntity. 它实现了接口IUserInputEntity。我目前将它声明为类型的局部变量,UserInputEntity因此不能在以下方法中模拟它(为简洁起见):

public void CompletionReportNotifier(object sender, VerificationStatusEventArgs e)
{
    _view.PermanentCsvFileVerificationCancellation = null;

    string logMessage;
    bool inputsVisible = false;

    //Mocking inputs.NumberOfErrorsFound??
    if (e.CarriedOutToCompletion != true || inputs.NumberOfErrorsFound > 0)
    {
        inputsVisible = true;
        _view.VerificationCompleted = false;
        logMessage = "failed to complete operation";
    }
    else
    {
        _view.VerificationCompleted = true;
        logMessage = "Completed operation";
    }
    _view.UIUpdate(logMessage, inputsVisible);
}

解决这个问题的最合适方法是什么?我能想到的唯一可能的解决方案是声明另一个只调用实体类构造函数的方法,并返回一个IUserInputEntity. 然后我会inputs在演示者中将 的声明更改为 type IUserInputEntity。这会合适还是有更好的方法?

以下是当前创建实例的方法的副本inputs(简化):

private void DataVerification(Object sender, EventArgs e)
{
    if (_view.VerifyingData != true)
    {
        inputs = new UserInputEntity(_view.DataTypeInputs, _view.ColumnNameInputs, _view.InitialRow, _view.FinalRow, _view.CurrencyPair, _view.CsvFilePath, _view.ErrorLogFilePath);

        // ...

        verification.VerifyDataTypesAsync();     
    }
    else
    {
        _view.PermanentCsvFileVerificationCancellation.Cancel();
    } 
}
4

3 回答 3

1

当遵循依赖注入模式时,任何使用关键字“new”的行为都应该非常谨慎和恐惧。机会非常好,它正是应该注入的那些依赖项之一。这绝对是那些时代之一。

这里真正的解决方案是添加IUserInputEntity到您的构造函数并将其抽象出来,以便您的控制容器反转(StructureMap、NInject 等)自动注入。在结构图中,这看起来有点像这样:

public class DependencyRegistry : Registry
{
    public DependencyRegistry()
    {
        For<IUserInputEntity>().Use<UserInputEntity>();
    }
}

使用类用法:

public MyClass(IUserInputEntity userInputEntity)
{
   _userInputEntity = userInputEntity;
}

然后,您可以设置您所知道的属性或在您的具体类中自由使用它们。在您的测试中,它看起来像这样(假设是 NUnit 和 RhinoMocks):

[Test]
public void MyTest()
{
   var mockEntity = MockRepository.GenerateMock<IUserInputEntity>();

   var testedClass = new MyClass(mockEntity);
}

此时,您可以使用 RhinoMocks 提供的各种控制方法或任何您的模拟框架来训练模拟实体。这里要注意的重要一点是,您没有传递UserInputEntity该功能的具体实现,您如何编写具体的功能。您正在传递一个模拟,它将完全按照您的指示去做,仅此而已。

于 2012-08-27T16:07:19.090 回答
1

您将不得不在这里的某个时候模拟一个依赖项。很难说这个例子中唯一的错误耦合是直接在视图中实例化的 IUserInputEntity 还是_view耦合也是错误的。该示例没有显示是否_view实现了接口,但它应该。在 MVP 模式中,演示者在视图和模型之间进行调解。

如果视图负责收集用户输入,那么您需要在视图上模拟一个返回 an 的方法,IUserInputEntity以便演示者可以访问它。我认为需要将数据验证传递给模型类(使用 YYY 在他的回答中使用的示例)。现在模型可以验证来自任何类型 IView 的输入。

因此,更新您的视图以采用IUserInputEntityYYY 的答案,并更新演示者以使用 DI 来[IYourViewInterface]模拟来自视图的不同类型的输出。在您的演示者中使用这些接口,并让您的视图和模型类在其构造函数中获取依赖关系,以最大限度地提高应用程序的可测试性。

于 2012-08-27T16:48:56.780 回答
0

在方法中创建的对象的实例。如何模拟该实例?

这就是工厂或供应商的用途。理想情况下,应该注入工厂/提供者,以便您修复将返回的内容。

这假定new是必需的。如果不是(即它是无状态服务),那么您应该简单地注入该服务。

最后一个选项,不容忽视的是:使用真正该死的对象。如果协作者中包含的逻辑并不复杂,并且没有任何依赖关系,并且对象相当笨拙,那么经过良好测试且易于设置,而不仅仅是使用它会比模拟它更痛苦。

于 2012-08-28T13:05:40.263 回答