3

I am new to unit testing, so pardon me if I am unable to explain this question properly. I am reading a book "The art of Unit Testing 2nd Edition" and trying to implement unit testing in my project. I am currently stuck or confused when testing using mocking (using NSubstitute as the mocking framework).

Here is my scenario:

I have two interfaces ICommand and IUser

 public interface ICommand
 {
        string execute();
 }

 public interface IUserCalendar
 {
    string LoadCalendar();
 }

I have a class LoadCalendar which implements ICommand:

public class LoadCalendar : ICommand
{
    private IUserCalendar user;

        public string execute()
        {
            return this.user.LoadCalendar();
        }

        public LoadCalendar(IUserCalendar obj)
        {
            this.user = obj;
        }
}

ViewCalendar implements IUserCalendar:

public class Viewer : IUserCalendar
{    
        public string LoadCalendar()
        {
            return "Viewer Load Calendar Called";
        }  
}

Using an agent class I am invoking command for specific request. (Here I am showing only one request LoadCalendar for one user viewer but I have more command and more users)

My client has an invoker object that invokes the command for specific user.

 public class Client
 {    
        public Client()
        { }  

        public string LoadCalendar(ICommand cmd)
        {
            Invoker invoker = new Invoker(cmd);
            return invoker.execute();
        }    
}

Now I like to test the client class that when it calls for specific user it should return proper object or message.

[Test]
public void client_Load_Calendar_Administrator()
{
            IUserCalendar calanedar = Substitute.For<IUserCalendar>();
            ICommand cmd = Substitute.For<ICommand>(calanedar);

            Client c = new Client();
            c.LoadCalendar(cmd, calanedar).Returns(Arg.Any<string>());
}

I don't know where I am doing wrong and it's throwing an error.

NSubstitute.Exceptions.SubstituteException : Can not provide constructor arguments when substituting for an interface.

Any help is really appreciated. Sorry for long question.

marc_s
  • 675,133
  • 158
  • 1,253
  • 1,388
fais
  • 145
  • 2
  • 14
  • Thanks for Editing Marc. If you know anyone who can answer this question please do forward to him. – fais Apr 06 '15 at 16:20

1 Answers1

3

The error you're getting:

Can not provide constructor arguments when substituting for an interface.

Is telling you exactly what's wrong.

You're passing in constructor arguments here:

ICommand cmd = Substitute.For<ICommand>(calanedar);

Of course, interfaces never have a constructor. You're trying to interact with your ICommand interface as if it were your concrete LoadCalendar implementation of it.

Furthermore, to be able to unit test a class you always want to have a default (parameterless) constructor. Many mocking frameworks actually require this.

In this case you should probably test against the concrete class and mock/substitute the classes that it uses.

Either that, or you only substitute ICommand simply to have it return a pre-set (string) value. Then you can proceed to verify if the code that consumes your command, actually invokes it and/or does the correct thing with the value it returns.

To illustrate:

[Test]
public void client_Load_Calendar_Administrator()
{
    // You are substituting (mocking) the IUserCalendar here, so to test your command
    // use the actual implementation
    IUserCalendar calendar = Substitute.For<IUserCalendar>();

    ICommand cmd = new LoadCalendar(calendar):

    // Let the IUserCalendar.LoadCalendar() return a certain string
    // Then Assert/Verify that cmd.Execute() returns that same string
}

That's the point of unit testing: you test the smallest piece of functionality by mocking all dependencies. Otherwise it's an integration test.

To test your client:

[Test]
public void client_Load_Calendar_Administrator()
{
    ICommand cmd = Substitute.For<ICommand>();

    Client c = new Client();
    // Let your command return a certain string
    // Then verify that your calendar returns that same string
}

EDIT: In case you're interested, the method in NSubstitute that throws this exception:

private void VerifyNoConstructorArgumentsGivenForInterface(object[] constructorArguments)
{
    if (constructorArguments != null && constructorArguments.Length > 0)
    {
        throw new SubstituteException("Can not provide constructor arguments when substituting for an interface.");
    }
}

They're pretty clear about it: no constructor arguments for an interface substitute, no matter what.

Fred Kleuver
  • 7,307
  • 2
  • 22
  • 35
  • Can you provide me more details about Integration Testing? Any link or any book reference is really appreciated – fais Apr 06 '15 at 16:47
  • This link might be interesting for you: http://stackoverflow.com/questions/5357601/whats-the-difference-between-unit-tests-and-integration-tests. Sorry that I couldn't provide you with a working code example - I'm not familiar with NSubstitute, I personally use Moq. So I wouldn't know the exact semantics of how to accomplish what I was trying to explain. I can provide a more complete example done with Moq and XUnit if you like? – Fred Kleuver Apr 06 '15 at 16:52