0

We're using NSubstitute, so I think we need a single interface to mock. We also have code that references the superclass and using polymorphism.

Ideas I had..

Create an interface with both the methods I've added and the existing ones (e.g. Value and Text), and change references in existing code to use that interface rather than superclass directly?

Wrap the TextBox rather than subclass it (not sure - is this the Adapter / Proxy pattern).

Update (Elaboration):

We've made a ValueTextBox class, which subclasses TextBox and adds a Value Property:

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

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

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

We want to assert that other code is calling get/set Text/Value at the expected times.

Notes:

  1. We have another class IntegerTextBox, similar to ValueTextBox.
  2. Our other code sometimes stores ValueTextBox/IntegerTextBox objects in variables of type TextBox, taking advantage of polymorphism.
Sam
  • 581
  • 4
  • 17

3 Answers3

1

The general advice is to not Mock what you don't own. (Since you didn't write/control the TextBox class, you shouldn't mock it.)

But your situation is your situation. So if you could elaborate a bit more on why you need this? We could figure out alternatives.

Update: it seems like you're bringing all controls down to a common level - a role(interface) called ValueProvider. In which case, you could write a common test fixture, which accepts an implementation (as input) and verifies if the ValueProvider.Value Property works as expected. Pass in different implementations of ValueProvider. Is there a reason you want to mock the base type ? You can just create an instance of your custom derivation and invoke the Value property to see if it works.

Gishu
  • 134,492
  • 47
  • 225
  • 308
0

If you can add a bit more info on the code you are trying to test that would be great. Based on what you've written I can guess at a couple of options.

Least invasive at the moment would probably be the approaches you suggested in your question: add an interface or common base class/adapter with the member you want to fake out as virtual so it can be picked up by mocking libraries that use dynamic proxy (like NSubstitute, Moq, FakeItEasy and Rhino Mocks).

If you had something like IInputControl<T> which had T Value { get; set;} on it then you could substitute for that type in your tests. You would have to update the code to store references as IInputControl<T> rather than TextBox, but that may not be a bad thing as it isolates the code from the details of TextBox.

The other option (not sure if you are doing this already) is to use a Model-View-Presenter style, and do not unit test the specifics of how the view translates messages into TextBox or other controls. (You could use acceptance tests for end to end testing.)

As an example, say you had a presenter and view interface like this:

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

Your could test with something like this:

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

Your actual view can then delegate to the existing controls. This is untested by unit tests, but might be acceptance testable, or be manually tested whenever the view is changed. Ideally this code should be simple enough to not hide too many bugs; the idea is to make the view as simple as possible, and to primarily be concerned with the appearance of the information, rather than with logic.

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; }
  }
}
David Tchepak
  • 9,826
  • 2
  • 56
  • 68
0

Building on your own idea of creating an interface, and on Gishu's answer of the ValueProvider, create your interface like this:

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

and then make your ValueTextBox like this:

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

You can then mock an IValueProvider.

Community
  • 1
  • 1
ClickRick
  • 1,553
  • 2
  • 17
  • 37