eych
eych

Reputation: 1272

Unit testing a method with multiple interface calls

As a unit test newbie, I've been reading that one test should be for one method.
So, what is the way for testing the method DoStuff below?

Is it three separate tests, with proper Setup's for each interface case?
Or, is it one test with Setup's and Returns, more like a Strict behavior?

public class MainClass
{
    IFoo myFoo;
    IBar myBar;
    IBaz myBaz;

    public MainClass(IFoo foo, IBar bar, IBaz baz) {
        this.myFoo= foo;
        this.myBar= bar;
        this.myBaz= baz;
    }

    public void DoStuff(string myParam) {
        var fooResult = myFoo.doFoo(myParam);
        myBar.doBar(fooResult);
        myBaz.doBaz();
    }
}

Upvotes: 0

Views: 57

Answers (2)

I'll take the liberty to use NSubstitute instead of moq, but you can probably figure out the way to do it with moq yourself. I'll also be using AutoFixture.Xunit2 because it is awesome.

private MainClass _target;
private IFoo _foo = Substitue.For<IFoo>();
private IBar _bar = Substitute.For<IBar>();
private IBaz _baz = Substitute.For<IBaz>();

public MainClassTest()
{
    _target = new MainClass(_foo, _bar, _baz);
}

[Theory, AutoData]
public void DoStuff_Delegates_To_Foo(string myParam)
{
    _target.DoStuff(myParam);
    _foo.Received.DoFoo(Arg.Is(myParam));
}

[Theory, AutoData]
public void DoStuff_Calls_Bar_With_Result_From_Foo(string myParam, object fooResult)
{
    _foo.DoFoo(Arg.Is(myParam)).Returns(fooResult);

    _target.DoStuff(myParam);

    _bar.Received().DoBar(Arg.Is(fooResult));
}

[Theory, AutoData]
public void DoStuff_Calls_Baz_After_Foo_And_Bar(string myParam)
{
    _target.DoStuff(myParam);

    Received.InOrder(() => 
    {
        _foo.DoFoo(Arg.Any<string>());
        _bar.DoBar(Arg.Any<object>());
        _baz.DoBaz();
    }
}

The idea is to have a test method for each thing you want to know about the DoStuff method. The above are only examples, if you want to you could also just write it all in one test. Here the challenge is to come up with a good description of what you test (so imagine you name the test and your colleague implements it), anyway, here follows an example of a badly named test method, that tests everything.

[Theory, AutoData]
public void DoStuff_Does_What_It_Is_Supposed_To_Do(string myParam, object fooResult)
{
    _foo.DoFoo(Arg.Is(myParam)).Returns(fooResult);

    _target.DoStuff(myParam);

    Received.InOrder(() => 
    {
        _foo.DoFoo(Arg.Is(myParam));
        _bar.DoBar(Arg.Is(fooResult));
        _baz.DoBaz();
    }
}

So to answer your question, it comes down to naming. If you can describe the test in one short sentence, then go ahead and do it. You've probably heard that each test method should test one thing and only one thing, and it helps if you think of "thing" in this context as something you can describe in a single short sentence.

Upvotes: 1

Spock
Spock

Reputation: 6992

I've been reading that one test should be for one method

This is not true. You may have multiple Unit Tests for a method.

In "DoStuff", there is no real behavior/logic apart from calling myFoo and and myBar.

There is no much value you get Unit Testing this routine IMO. Very similar to a service call that orchestrate routines.

Upvotes: 1

Related Questions