Nunit testing with Mock. Instance of Interface

30,317

Solution 1

You need to configure the Mock object to return something for IService.method as follows:

var Service = new Mock<IService>();
Service.Setup(x => x.method(It.IsAny<string>())
    .Returns<string>(str => **whatever result you need**);

With the addition of your actual IService definition, you should change the Setup call to:

Service.Setup(x => x.method(It.IsAny<ApplicationUser>(), It.IsAny<UserLoginInfo>())
    .Returns<ApplicationUser, UserLoginInfo>((user, login) => new IdentityResult(true));

Solution 2

The setup method has to be called on the Mock object.

var Service = new Mock<IService>();
Service.Setup(x=>x.method("argument")).Returns(YourReturnObject)
Controller _controller = new Controller(Service.Object);

Solution 3

Using your simplified example

public class Controller
{
     private readonly IService _service;

     public Controller(IService service)
     {
         _service = service;
     }

     public async Task<IHttpActionResult> Create(string content)
     {
         var result = await _service.method(content);
         if (!result.Succeeded)
         {
            return this.GetErrorResult(result);
         }
         return Ok();
     }
}

Lets assume IService is defined as

public interface IService {
    Task<Result> method(string input);
}

public class Result {
    public bool Succeeded { get; set; }
}

For the unit test you need to setup the mock to fake the actions wanted for the test

public async Task Controller_Given_Content_Should_Return_Ok() {
    //Arrange
    var input = "content";
    var mockService = new Mock<IService>();
    mockService
        .Setup(m => m.method(input))
        .ReturnAsync(new Result { Succeeded = true }); 
    var _controller = new Controller(mockService.Object);

    //Act
    var result = await _controller.Create(input);

    //Assert
    Assert.IsNotNull(result);
    Assert.IsInstanceOfType(result,typeof(OkResult));
}

Given that the method under test is asynchronous you would want to setup the test to be asynchronous as well.

Share:
30,317
Alex
Author by

Alex

Updated on January 13, 2020

Comments

  • Alex
    Alex over 4 years

    I have the following (simplified) code.

    public class Controller
    {
         private readonly IService _service;
    
         public Controller(IService service)
         {
             _service = service;
         }
    
         public async Task<IHttpActionResult> Create(MyObject object)
         {
             var result = _service.method(object);
             if (!result.Succeeded)
             {
                return this.GetErrorResult(object);
             }
         }
    }
    

    and SimpleInjector is used to inject the dependency between _service and its implementation class, like this:

    public static void Register(Container container)
    {
        container.Register<IService, Service>();
    }
    

    As a note, injection and unit testing are new to me so I do not fully understand them, but am learning.

    If I run the application through Swagger, all is working fine.

    As a note, the Register function is called when I run the application through Swagger.

    Now, I am trying to setup some unit tests using NUnit, and am Mocking the IService object like this:

    var Service = new Mock<IService>();
    Controller _controller = new Controller(Service.Object);
    _controller.Create(new MyObject object());
    

    which seems to be correct to me so far - although I am not sure?

    The problem is that for the unit test, result is always null - I think the is because there is a problem with my Mock of the interface - it does not seem to be finding the method - it never steps into it and does not show up int he debugger.

    As a note, for the unit test, the Register method does not get called. I did try calling it to register the dependency, but it does not help.

    As I said above, this is all new to me and I am on the edge of my understanding on all of this.

    I am out of ideas and do not know where to look from here, so any help would be greatly appreciated.

    EDIT:

    The original question had the following:

    public async Task<IHttpActionResult> Create(string content)
    

    which I have updated to:

    public async Task<IHttpActionResult> Create(MyObject object)
    

    Can anyone advise how I can pass in a generic reference to MyObject on the setup, without having to make an instance of this class.

    So basically I want to tell it that an instance of this class will be passed in, without creating that instance.

    I have tried the following:

    Service.Setup(x => x.method(It.IsAny<MyObject>())
    
    but it says cannot convert MethodGroup to MyObject
    

    and here is the definition of IService:

    public interface IService
    {
          IdentityResult method(ApplicationUser user, UserLoginInfo login);
    }
    
  • Chris Pickford
    Chris Pickford over 7 years
    Please add the definition of IService to your question.
  • Alex
    Alex over 7 years
    I have posted the IService definition
  • Alex
    Alex over 7 years
    thank you - I really appreciate your help. I had this: Service.Setup(x => x.method(It.IsAny<MyObject>, It.IsAny<MyObject>)) - So close!
  • Nkosi
    Nkosi over 7 years
    @Alex in future provide a minimal reproducible example emphasis on complete so that you can get better answers without a lot of back and forth asking for clarifications.