stefo0O0o
stefo0O0o

Reputation: 119

mocked method won't return object

im using .net mvc3 to build simple app. I wrote couple of test cases and i have problem with one of them. Im using Moq to mock my domain service, i have this two methods:

List<Customer> customersRepo =
{
  new Customer{
   Id = 0,
   Name = "Jojo"
  },
  new Customer{
   Id = 1,
   Name = "John"
  }
}

mock.Setup(m => m.GetByName(IsAny<string>())).Returns<string>(
 n =>
 customersRepo.Where(c => c.Name == n)
);

mock.Setup(m => m.GetById(IsAny<int>())).Returns<int>(
  n=>
  customersRepo.Where(c => c.Id == n)
);

The problem is that when i use the mock object's method to fetch customer by name i get the one i asked for, but when i try to fetch by id i always get null object from the mock object.. i tried both with id 0 and 1.. What can be the problem?

Thanks

Upvotes: 0

Views: 510

Answers (2)

stefo0O0o
stefo0O0o

Reputation: 119

I actually just changed a bit my infrastructure.. now my service get's DataSource interface object in the constructor.. which is independent data source and it relies on it to get customer objects, ofc. after it checks for the business rules and does any needed sanitation of the user input.. So now, i will just mock my data source (a list with customer objects) in the unit test and feed an instance of my service with this mocked repo of customer objects.. this way i can test my already coded service business logic for correctness. Previously i had coupled the service with specific data storage (that is db using EF DbContext) and it was a bit hard to use the service in the unit test since it was already coupled with the db, but i didn't wanted to alter and revert back the db state just to perform my unit-tests, so i wanted to simulate the data storage with simple list of customer objects.. Thanks for your efforts, helped me there :)

Upvotes: 0

Sergey Berezovskiy
Sergey Berezovskiy

Reputation: 236188

I think you should return first or default customer:

mock.Setup(m => m.GetById(IsAny<int>())).Returns<int>(
  id =>
  customersRepo.FirstOrDefault(c => c.Id == id)
);

Also keep in mind, that you don't need to re-implement your repository logic in mocks (that is weird and very fragile). It is mock. You can mock any result you want without any logic:

mock.Setup(m => m.GetById(42)).Returns<int>(new Customer { Id = 42 });

Use mocks to verify interaction - i.e. that clients of your repository called expected method with expected parameters.


If you want to test business logic of some service, then service is a system under test (SUT) and you should not mock it. But if your service has both business logic and data access logic, then it does too many things. Extract data access logic to some repository class, which will implement interface:

public interface ICustomerRepository
{
    Customer GetById(int id);
    // other methods related to customr data access
}

Then make your service depend on this interface (dependency inversion):

public class YourService
{
   private readonly ICustomerRepository _repository;
   // dependency injection
   public YourService(ICustomerRepository repository)
   {
       _repository = repository;
   }

   public void ExecuteSomeBusinessLogic()
   {
       // your code will go here
   }
}

Then write tests for service. Thus service requires dependency (customer repository) you should mock this dependency. And verify that service interacts with dependency as you expect. E.g. in your ExecuteSomeBusinessLogic test we should check that service will ask for customer with id equal to 42 (yep, weird business logic):

[Test]
public void ShouldPerformGoodStuffWhenCustomerFound()
{
    // Arrange
    var mockRepository = new Mock<ICustomerRepository>();
    mockRepository.Setup(r => r.GetById(42)).Returns(new Customer { Id = 42 });
    var service = new YourService(mockRepository.Object);
    // Act
    service.ExecuteSomeBusinessLogic();
    // Assert
    mockRepository.VerifyAll();
    // check other stuff
}

If you will write test for case when custom was not found in database, just setup different returns:

mockRepository.Setup(r => r.GetById(42)).Returns(null);

Upvotes: 1

Related Questions