Search code examples
c#unit-testingnmock

How to mock a function in an unit test


How could I unittest GetData by NMock3?

It would be great if prcessA.Run and the "result" inside ProcessA could be mocked.

IAnotherService could not be GetData's parameter as it depends on a processed value inside GetData.

Any ideas?

Service1

public class Service1 : IService1
{
    public Service1()
    {
    }

    public string GetData(int a)
    {
        // some process depends on input
        int b = a * new Random().Next();

        IAnotherService anotherService = new AnotherService(b);
        ProcessA processA = new ProcessA(anotherService);
        processA.Run();
        return processA.result;
    }
}

Simplified ProcessA

public class ProcessA
{
    public string result;
    private IAnotherService anotherService;

    public ProcessA(IAnotherService anotherService)
    {
        this.anotherService = anotherService;
    }

    public void Run()
    {
        // Some other process here
        this.result = this.anotherService.Run();
    }
}

TestMethod1

[TestMethod]
public void TestMethod1()
{
    using (mockFactory.Ordered())
    {
        // Nothing to Mock
    }

    IService1 service1 = new Service1();
    string aaa = service1.GetData(1);

    Assert.AreEqual("XXX", aaa);
}

Solution

  • As discussed, you need to mock out the dependent services and set up what you are expecting to return.

    I've done a test below and it works. I use Moq, but the principal is the same.

     public interface IAnotherService
     {
         string Run();
     }
    
    public class ProcessA
    {
        public string result;
        private readonly IAnotherService _anotherService;
    
        public ProcessA(IAnotherService anotherService)
        {
            this._anotherService = anotherService;
        }
    
        public string Run()
        {
            // Some other process here
            return _anotherService.Run();
        }   
    }
    

    Then run the test

    [Test]
    public void TestMethod1()
    {
       //Create a Mock
       var mockService = new Mock<IAnotherService>();
       //Set the expected result
       mockService.Setup(method => method.Run()).Returns("XXX");
    
       //Inject the mock
       var process = new ProcessA(mockService.Object);
       var result = process.Run();
    
       //Assert the result     
       Assert.AreEqual("XXX", result);
    }
    

    EDIT

    As discussed, I've edited my answer to hopefuly what you need.

     public interface IService1
        {
            string GetData(int a);
            int ValueForB { get; set; }
        }
    
    public class Service1Consumer : IService1
    {
        private readonly IAnotherService _anotherServiceImplementation;
    
        public Service1Consumer(IAnotherService service)
        {
            _anotherServiceImplementation = service;
        }
    
        public string GetData(int a)
        {
            ValueForB = a * new Random().Next();
            _anotherServiceImplementation.ValueFor = b;
            var processA = new ProcessA(_anotherServiceImplementation);
            return processA.Run();
        }
    }
    
    public interface IAnotherService
    {
        int ValueForB { get; set; }
    }
    
    public class AnotherService : IAnotherService
    {
    }
    
    public class ProcessA
    {
        public string result;
        private readonly IAnotherService _anotherService;
    
        public ProcessA(IAnotherService anotherService)
        {
            _anotherService = anotherService;
        }
    
        public string Run()
        {
            return "XXXX";
        }
    }
    

    Then the test.

      [Test]
      public void TestMethod1()
      {
          //Create a Mock
          var mockAnotherService = new Mock<IAnotherService>();
          //Set the property value when called.
          mockAnotherService.Setup(method => method.ValueForB).Returns(10);//Test 1
    
          var service1Consumer = new Service1Consumer(mockAnotherService.Object);
          var result = service1Consumer.GetData();
    
          Assert.AreEqual("XXXX",result);
    
       }
    

    Hope that points you in the right direction. Thanks