在没有模拟框架的情况下编写单元测试

时间:2018-08-30 11:50:11

标签: c# nunit nsubstitute

我正在使用NUnit和NSubstiture进行一些单元测试。

我上了这个课:

public class Presenter
{
    public Presenter()
    {
    }

    private readonly IView _view;
    public Presenter(IView view)
    {
        _view = view;
        this._view.Loaded += OnLoaded;
    }
    private void OnLoaded()
    {
        _view.Render("Hello Word");
    }
}

我有这个界面:

public interface IView
{
    event Action Loaded;
    void Render(string text);
}

我已经使用NSubstiture框架进行了单元测试,如下所示:

[Test]
public void ctor_WhenViewIsLoaded_CallsViewRender_WithMockingFramework()
{
    var mockView = Substitute.For<IView>();
    Presenter p = new Presenter(mockView);
    mockView.Loaded += Raise.Event<Action>();
    mockView.Received().Render(Arg.Is<string>(s => s.Contains("Hello World")));
}

但是现在我只是出于测试目的,编写相同的单元测试,但是没有NSubstiture框架:

[Test]
public void ctor_WhenViewIsLoaded_CallsViewRender_WithoutMockingFramework()
{
    IView view;
    Presenter MockingVIew = new Presenter(view);
}

但是怎么做?

谢谢

我这样尝试:

public class FakePresenter : IView
{
    public event Action Loaded;

    public void Render(string text)
    {
    }
}

[Test]
public void ctor_WhenViewIsLoaded_CallsViewRender_WithoutMockingFramework()
{
    //FakeMockingVIew = new Presenter(view);
    FakePresenter fPresenter = new FakePresenter();
    Presenter p = new Presenter(fPresenter);
    fPresenter.Loaded += Raise.Event<Action>();
    fPresenter.Received();
    Assert.That(fPresenter, Is.EqualTo());
}

2 个答案:

答案 0 :(得分:1)

如果您不再想使用模拟框架,那么什么都不会阻止您自己创建从IView派生的类并将其用作测试中的依赖项

public class MyTestClass {

    public class FakePresenter : IView {
        public event Action Loaded = delegate { };

        public void Render(string text) {
            RenderedText = text;
        }

        public string RenderedText { get; private set; }

        public void Load() {
            Loaded();
        }
    }

    [Test]
    public void ctor_WhenViewIsLoaded_CallsViewRender_WithoutMockingFramework() {
        //Arrange
        var fake = new FakePresenter();
        var subject = new Presenter(fake);
        var expected = "Hello Word";

        //Act
        fake.Load();
        var actual = fake.RenderedText;

        //Assert
        Assert.AreEqual(expected, actual);
    }
}

上述依赖关系的实现公开了一个Load()方法来引发所有订阅者的事件,还公开了一个RenderedText属性来捕获传递到Render方法中的文本,以便声明可以根据该值进行。

答案 1 :(得分:0)

使用NSubstitute时,必须告诉模拟视图引发事件。但是由于IView界面不允许您触发该事件,仅添加一个事件侦听器,NSubstitute通过附加一个特殊的事件处理程序来进行工作,实际上触发了一个事件(我不是熟悉NSubstitute,但我认为这是会发生的事情:

// Code here says "attact an event handler", but NSubstitute recognizes this 
// special event handler and raises the event to the "real" hanlders instead
mockView.Loaded += Raise.Event<Action>();

因此,当您离开NSubstitute时,实际上需要从假视图类以“正确”的方式触发事件:

public class FakeView : IView
{
    private string RenderedText { get; private set; }
    public event Action Loaded;

    public void Render(string text)
    {
        renderedText = text;
    }

    public void RaiseLoaded() {
        if (Loaded != null) Loaded();
    }
}

现在,您可以轻松触发测试中的事件:

[Test]
public void ctor_WhenViewIsLoaded_CallsViewRender_WithoutMockingFramework()
{
    FakeView view = new FakeView();
    Presenter p = new Presenter(fPresenter);
    view.RaiseLoaded();
    Assert.That(view.RenderedText, Is.EqualTo("Hello World"));
}