0

我们正在使用 NSubstitute,所以我认为我们需要一个单独的接口来模拟。我们还有引用超类并使用多态性的代码。

我的想法..

使用我添加的方法和现有方法(例如 Value 和 Text)创建一个接口,并更改现有代码中的引用以使用该接口而不是直接使用超类?

包装 TextBox 而不是子类化它(不确定 - 这是适配器/代理模式)。

更新(细化):

我们创建了一个 ValueTextBox 类,它是 TextBox 的子类并添加了一个 Value 属性:

public class ValueTextBox : TextBox
{
    /* ... */

    public ValueTextBox(/* ... */)
    {
        /* ... */
    }

    public string Value
    {
        get
        {
            /* ... */
        }
        set 
        {
            /* ... */
        }
    }
}

我们想要断言其他代码在预期的时间调用 get/set Text/Value。

笔记:

  1. 我们还有另一个类 IntegerTextBox,类似于 ValueTextBox。
  2. 我们的其他代码有时利用多态性将 ValueTextBox/IntegerTextBox 对象存储在 TextBox 类型的变量中。
4

3 回答 3

1

一般的建议是不要模拟你不拥有的东西。(由于您没有编写/控制 TextBox 类,因此您不应该模拟它。)

但你的情况就是你的情况。所以,如果你能详细说明你为什么需要这个?我们可以找出替代方案。

更新:似乎您正在将所有控件降低到一个通用级别 - 一个名为 ValueProvider 的角色(接口)。在这种情况下,您可以编写一个通用测试夹具,它接受一个实现(作为输入)并验证 ValueProvider.Value 属性是否按预期工作。传入 ValueProvider 的不同实现。您是否有理由要模拟基本类型?您可以创建自定义派生的实例并调用 Value 属性以查看它是否有效。

于 2012-04-05T12:21:39.417 回答
0

基于您自己创建界面的想法,以及Gishu对 ValueProvider 的回答,创建您的界面,如下所示:

interface IValueProvider
{
    string Value {get; set; }
}

然后ValueTextBox像这样:

public class ValueTextBox : TextBox, IValueProvider
{
    public string Value
    {
        get { /* ... */ }
        set { /* ... */ }
    }
}

然后你可以模拟一个IValueProvider.

于 2014-05-17T10:27:46.380 回答
0

如果您可以在您尝试测试的代码上添加更多信息,那就太好了。根据您所写的内容,我可以猜到几个选项。

目前侵入性最小的可能是您在问题中建议的方法:为您想要伪造的成员添加一个接口或公共基类/适配器,virtual以便可以通过模拟使用动态代理的库(如 NSubstitute 、起订量、FakeItEasy 和 Rhino 模拟)。

如果您有类似的东西IInputControl<T>T Value { get; set;}那么您可以在测试中替换该类型。您必须更新代码以将引用存储为IInputControl<T>而不是TextBox,但这可能不是一件坏事,因为它将代码与TextBox.

另一种选择(不确定您是否已经这样做了)是使用 Model-View-Presenter 样式,并且不要对视图如何将消息转换为TextBox其他控件的细节进行单元测试。(您可以使用验收测试进行端到端测试。)

例如,假设您有一个演示者和视图界面,​​如下所示:

public class PersonPresenter {
  public PersonPresenter(IPersonView view, IPersonQuery query) { ... }

  public void Load() {
    var person = query.Execute();
    view.Name = person.Name;
    view.Age = person.Age;
  }
}

public interface IPersonView {
  string Name { get; set; }
  int Age { get; set; }
}

你可以用这样的东西进行测试:

[Test]
public void ShouldDisplayPersonOnLoad() {
  var view = Substitute.For<IPersonView>();
  var query = Substitute.For<IPersonQuery>();
  query.Execute().Returns(new Person("A", 20));

  var subject = new PersonPresenter(view, query);
  subject.Load();

  Assert.That(view.Name, "A");
  Assert.That(view.Age, 20);
}

然后,您的实际视图可以委托给现有控件。这未经单元测试测试,但可能是可验收测试的,或者在视图更改时手动测试。理想情况下,这段代码应该足够简单,不会隐藏太多错误;这个想法是使视图尽可能简单,并且主要关注信息的外观,而不是逻辑。

public PersonView : IPersonView {
  // ...
  public string Name { 
    get { return nameTextBox.Value; } 
    set { nameTextBox.Value = value; }
  }
  public int Age { 
    get { return ageIntTextBox.Value; } 
    set { ageIntTextBox.Value = value; }
  }
}
于 2012-04-06T00:04:34.120 回答