Can someone show me how I can mock the result of a method in a base abstract class? See the very basic sample code below to demonstrate the problem and I need to mock the “GetAge()” method’s result. See the commented line at the end with the ending "<----- FIX here" where I think need to add the fix.
Customer Service
public interface ICustomerService
{
string GetCustomerDetailsSrv(int age);
}
public class CustomerService : ICustomerService
{
public string GetCustomerDetailsSrv(int age)
{
return $"Name: John Doe. Age: {age}";
}
}
Base Controller
public abstract class MyBaseController : ControllerBase
{
public virtual int GetAge()
{
return 7;
}
}
Customer Controller
public class CustomerController : MyBaseController
{
private readonly ICustomerService _customerSrv;
public CustomerController(ICustomerService customerSrv)
{
_customerSrv = customerSrv;
}
[HttpGet]
public string GetCustomerDetails()
{
var age = GetAge();
var result = _customerSrv.GetCustomerDetailsSrv(age);
return result;
}
}
Customer Controller Test
[TestClass]
public class CustomerControllerTest
{
private readonly CustomerController _controller;
private readonly Mock<ICustomerService> _mockSrv;
public CustomerControllerTest()
{
_mockSrv = new Mock<ICustomerService>();
_controller = new CustomerController(_mockSrv.Object);
}
[TestMethod]
public void TestGet()
{
//Arrange
int mockAge = 11;
string expectedResult = $"Name: Alice Smith. Age: {mockAge}";
// _controller.Setup(Controller => Controller.GetAge()).Returns(mockAge); <----- FIX here
_mockSrv.Setup(repo => repo.GetCustomerDetailsSrv(mockAge)).Returns(expectedResult);
//Act
var actualResult = _controller.GetCustomerDetails();
//Assert
Assert.IsTrue(actualResult == expectedResult);
}
}
I think the following code achieves what you want.
Creating a Mock from a CustomerController allows the setup the virtual method GetAge while still being able to use the GetCustomerDetails method from the CustomerController class.
[TestClass]
public class CustomerControllerTest
{
private readonly Mock<CustomerController> _mockController;
private readonly Mock<ICustomerService> _mockSrv;
public CustomerControllerTest()
{
_mockSrv = new Mock<ICustomerService>();
_mockController = new Mock<CustomerController>(() => new CustomerController(_mockSrv.Object));
}
[TestMethod]
public void TestGet()
{
//Arrange
int mockAge = 11;
string expectedResult = $"Name: Alice Smith. Age: {mockAge}";
_mockController.Setup(Controller => Controller.GetAge()).Returns(mockAge);
_mockSrv.Setup(repo => repo.GetCustomerDetailsSrv(mockAge)).Returns(expectedResult);
//Act
var actualResult = _mockController.Object.GetCustomerDetails();
//Assert
Assert.IsTrue(actualResult == expectedResult);
}
}
Related
I want to mock only some methods of a class and call the real implementation for other methods.
I have my sut class Test where the Runner class is injected in the constructor. This injected class has again a injected other class RunnerParam in the constructor.
The code is a simplified case of my real classes in trying to have only the basics.
[Fact]
public void Test()
{
var fixture = new Fixture().Customize(new AutoMoqCustomization());
var paramMock = fixture.Freeze<Mock<IRunnerParam>>();
paramMock.Setup(x => x.Multiplicator()).Returns(2);
var classMock = fixture.Freeze<Mock<IRunner>>();
classMock.Setup(x => x.Run()).Returns(5);
var test = fixture.Create<Test>();
var result = test.StartRunning(); // should be 5
var result2 = test.StartRunningImplementation(5); // should be 500
}
Supporting members
public interface IRunnerParam
{
int Multiplicator();
}
public class RunnerParam : IRunnerParam
{
public virtual int Multiplicator()
{
return 20;
}
}
public interface IRunner
{
int Run();
int RunImplementation(int param);
}
public class Runner : IRunner
{
protected virtual RunnerParam MultiParam { get; set; }
public Runner(RunnerParam multiParam)
{
MultiParam = multiParam;
}
public virtual int Run()
{
return 10;
}
public int RunImplementation(int param)
{
return 10 * MultiParam.Multiplicator() * param * Run();
}
}
public class Test
{
private readonly IRunner _runner;
public Test(IRunner runner)
{
_runner = runner;
}
public int StartRunning()
{
return _runner.Run();
}
public int StartRunningImplementation(int param)
{
return _runner.RunImplementation(param);
}
}
I want to mock and give a mocked value to the method Run in the class Runner, but to use the real implementation of the method RunImplementation.
I would expect to see for result2 500, but it's 0, meaning that the method is not seen as mocked up. In my eyes that is correct, but the Moq callbase is equal to true, so the real implementation should be taken, but it isn't.
What am I missing here?
In the shown simplified example, Test is only dependent on IRunner
private readonly IRunner _runner;
public Test(IRunner runner)
{
_runner = runner;
}
So that is all that needs to be mocked if the intention was to test Test class in isolation.
//...
var classMock = fixture.Freeze<Mock<IRunner>>();
classMock.Setup(x => x.Run()).Returns(5);
classMock.Setup(x => x.RunImplementation(It.IsAny<int>())).Returns(500);
//...
If Runner class is to be also tested in isolation, then a mocked RunnerParam would be needed to satisfy its dependencies.
It should however be dependent on the abstraction (interface) and not the concretion (implementation).
protected virtual IRunnerParam MultiParam { get; set; }
public Runner(IRunnerParam multiParam) {
MultiParam = multiParam;
}
This simplifies the isolated test as described in the original question
I want to mock and give a mocked value to the method Run in the class Runner, but to use the real implementation of the method RunImplementation.
//Arrange
var fixture = new Fixture().Customize(new AutoMoqCustomization());
var runnerParam = fixture.Freeze<Mock<IRunnerParam>>()
.Setup(_ => _.Multiplicator())
.Returns(2);
var subjectMock = fixture.Freeze<Mock<Runner>>();
subjectMock.CallBase = true;
subjectMock.Setup(_ => _.Run()).Returns(5);
int expected = 500;
Runner sut = subjectMock.Object;
//Act
var actual = sut.RunImplementation(5); // should be 500
//Assert
actual.Should().Be(expected);
I have an abstract class that I want to test. There is an abstract property in this class for my DAO, which I define in inherited classes.
public abstract class DeviceGroupManagerBase<TDeviceGroup> where TDeviceGroup : DeviceGroup
{
protected abstract IDeviceGroupDao<TDeviceGroup> DeviceGroupDao { get; }
public TDeviceGroup UpdateDeviceIndexes(Device device)
{
return DeviceGroupDao.GetDeviceGroup(device.Group.Id);
}
}
I want to test the Updatedeviceindexes method so I'm trying to mock a property called DeviceGroupDao.
[TestFixture]
[Category("Unit")]
public class DeviceGroupManagerBaseTests
{
private IFixture fixture;
private Mock<DeviceGroupManagerBase<DeviceGroup>> subject;
private Mock<IDeviceGroupDao<DeviceGroup>> deviceGroupDaoMock;
private DeviceGroupManagerBase<DeviceGroup> Manager => subject.Object;
[TestFixtureSetUp]
public void Init()
{
fixture = new Fixture().Customize(new AutoMoqCustomization());
deviceGroupDaoMock = fixture.Freeze<Mock<IDeviceGroupDao<DeviceGroup>>>();
subject = fixture.Freeze<Mock<DeviceGroupManagerBase<DeviceGroup>>>();
}
[Test]
public void TestUpdateDeviceIndexes()
{
var device = fixture.Create<Device>();
var deviceGroup = fixture.Create<DeviceGroup>();
deviceGroupDaoMock.Setup(x => x.GetDeviceGroup(It.IsAny<int>())).Returns(deviceGroup);
var result = Manager.UpdateDeviceIndexes(device);
// The resultDeviceGroup will not be contain a previously defined object
Assert.AreEqual(deviceGroup.Id, result.Id);
}
}
I also tried to add registration for my device object in this way:
fixture.Register(() => deviceGroup);
But I'm still getting a new object.
How can I mock IDeviceGroupDao<TDeviceGroup>?
Since DeviceGroupManagerBase is an abstract base class, you'll need a SUT Double. It's easiest to do if you make the DeviceGroupDao property public:
public abstract class DeviceGroupManagerBase<TDeviceGroup> where TDeviceGroup : DeviceGroup
{
public abstract IDeviceGroupDao<TDeviceGroup> DeviceGroupDao { get; }
public TDeviceGroup UpdateDeviceIndexes(Device device)
{
return DeviceGroupDao.GetDeviceGroup(device.Group.Id);
}
}
Otherwise, you'll need to use Moq's API for defining and overriding protected members, which is possible, but more work.
Then you'll need to override subject's DeviceGroupDao property:
subject.SetupGet(x => x.DeviceGroupDao).Returns(deviceGroupDaoMock.Object);
Here's the full test:
[TestFixture]
[Category("Unit")]
public class DeviceGroupManagerBaseTests
{
private IFixture fixture;
private Mock<DeviceGroupManagerBase<DeviceGroup>> subject;
private Mock<IDeviceGroupDao<DeviceGroup>> deviceGroupDaoMock;
private DeviceGroupManagerBase<DeviceGroup> Manager => subject.Object;
[OneTimeSetUp]
public void Init()
{
fixture = new Fixture().Customize(new AutoMoqCustomization());
deviceGroupDaoMock = fixture.Freeze<Mock<IDeviceGroupDao<DeviceGroup>>>();
subject = fixture.Freeze<Mock<DeviceGroupManagerBase<DeviceGroup>>>();
subject.SetupGet(x => x.DeviceGroupDao).Returns(deviceGroupDaoMock.Object);
}
[Test]
public void TestUpdateDeviceIndexes()
{
var device = fixture.Create<Device>();
var deviceGroup = fixture.Create<DeviceGroup>();
deviceGroupDaoMock.Setup(x => x.GetDeviceGroup(It.IsAny<int>())).Returns(deviceGroup);
var result = Manager.UpdateDeviceIndexes(device);
Assert.AreEqual(deviceGroup.Id, result.Id);
}
}
This now passes on my machine.
Because the DeviceGroupDao is protected you will need to find a way to access it externally. Create a stub that would allow you set it value.
public class DeviceGroupManagerBaseStub<TDeviceGroup>
: DeviceGroupManagerBase<TDeviceGroup> where TDeviceGroup : DeviceGroup {
private IDeviceGroupDao<TDeviceGroup> deviceGroupDao;
public DeviceGroupManagerBaseStub(IDeviceGroupDao<TDeviceGroup> deviceGroupDao) {
this.deviceGroupDao = deviceGroupDao;
}
protected override IDeviceGroupDao<TDeviceGroup> DeviceGroupDao {
get {
return deviceGroupDao;
}
}
}
You can then mock IDeviceGroupDao<TDeviceGroup> and inject it into the stub for your test.
Please see the code below:
[TestClass]
public class UnitTest1
{
Moq.Mock<ISayGoodMorning> GoodMorningMock;
[TestInitialize]
public void init()
{
GoodMorningMock = new Moq.Mock<ISayGoodMorning>();
GoodMorningMock.Setup(x => x.GoodMorning()).Returns(Test());
}
[TestMethod]
public void TestMethod1()
{
GoodMorningMock.Verify(x => x.GoodMorning(), Times.Once());
Assert.AreEqual(g.SayGreeting(), "Hola");
}
public string Test()
{
return "Hola";
}
}
The assert and the verify fail. Why is that? Here is the code that is tested:
namespace ClassLibrary1
{
public class SayGoodMorning : ISayGoodMorning
{
public string GoodMorning()
{
return "Good Morning";
}
}
public interface ISayGoodMorning
{
string GoodMorning();
}
}
namespace ClassLibrary2
{
public class Greeting
{
public string SayGreeting()
{
ISayGoodMorning s = new SayGoodMorning();
return s.GoodMorning();
}
}
}
First the subject under test needs to be refactored to inject the dependency to allow a mock to be used when testing. Either via constructor or method injection. (Explicit Dependencies Principle)
This example uses constructor injection
namespace ClassLibrary2 {
public class Greeting {
private readonly ISayGoodMorning speaker;
public Greeting(ISayGoodMorning speaker) {
this.speaker = speaker;
}
public string SayGreeting() {
return speaker.GoodMorning();
}
}
}
Next the test needs to be restructured so that the Verify is done after exercising the method under test;
[TestClass]
public class UnitTest1 {
Mock<ISayGoodMorning> GoodMorningMock;
[TestInitialize]
public void init() {
//Arrange
GoodMorningMock = new Mock<ISayGoodMorning>();
GoodMorningMock.Setup(_ => _.GoodMorning()).Returns(Test());
}
[TestMethod]
public void TestMethod1() {
//Arrange cont'd
var g = new ClassLibrary2.Greeting(GoodMorningMock.Object);
var expected = "Hola";
//Act
var actual = g.SayGreeting();
//Assert
GoodMorningMock.Verify(_ => _.GoodMorning(), Times.Once());
Assert.AreEqual(expected, actual);
}
public string Test() {
return "Hola";
}
}
I have a service class as below:
public class MyService
{
private readonly IMyDependency _myDependency;
public MyService(IMyDependency myDependency)
{
_myDependency = myDependency;
}
public void MyHandler(string param)
{
// work
}
public void AnotherMethod()
{
_myDependency.DoWork(MyHandler);
}
}
How can I Unit Test that MyHandler has been given as a parameter of DoWork()?
Since you are using Moq, you can write test like this:
[TestMethod]
public void DoWorkWasCalledWithCorrectParameters()
{
var mock = new Moq.Mock<IMyDependency>();
var myService = new MyService(mock.Object);
myService.AnotherMethod();
// verify that method was called once and with correct parameter:
mock.Verify(x => x.DoWork(myService.MyHandler), Moq.Times.Once);
}
I get the following error:
test.Services.JobService' does not contain a constructor that takes
0 arguments.
this is the code:
JobService.cs:
namespace TesteUltrafan.Services
{
public class JobService
{
private readonly IRepository _repository;
public JobService(IRepository repository)
{
_repository = repository;
}
public Job CreateJobBanker()
{
var banker = new Job();
string id = Guid.NewGuid().ToString("N");
Console.WriteLine("Novo job banker id: {0}", id);
banker.Id = id;
banker.Type = JobType.Banker;
banker.CreatedAt = DateTime.Now;
Console.WriteLine("Salvando job banker id: {0}", id);
Job jobBanker = _repository.SaveJob(banker);
return jobBanker;
}
}
}
the program.cs:
public class Program
{
public static void Main()
{
var jobService = new JobService(); <---- Here is the error.
Console.WriteLine("Creating job banker, creation:");
Job jobBanker = jobService.CreateJobBanker();
Console.WriteLine("Job banker: {0}", jobBanker);
}
}
Job.cs:
public class Job
{
public string Id { get; set; }
public DateTime CreatedAt { get; set; }
public JobType Type { get; set; }
}
JobType.cs:
public enum JobType
{
Actor = 1,
Agricultural = 2,
Banker = 3,
EngineerCivil = 4,
Another = 5,
}
You either need to create a parameterless constructor in your JobService class (which I would not do because then your class will not work correctly - there will be no reference to any repository) or preferably pass a Repository instance as a parameter when constructing this instance.
So the code should preferably look like this:
public class Program
{
public static void Main()
{
var jobService = new JobService(new Repository());
Console.WriteLine("Creating job banker, creation:");
Job jobBanker = jobService.CreateJobBanker();
Console.WriteLine("Job banker: {0}", jobBanker);
}
}
Where Repository should be a class implementing IRepository interface. Without passing this instance your CreateJobBanker will not work.
What would be though recommended is to use some IoC Container, because your code follows the Inversion of Control principle (probably you are not even aware of this).
Use
var jobService = new JobService(new Repository());
because otherwise your JobService with not have an IRepository instance and will throw a NullReferenceException when you try to use your repository inside JobService.
In your code, you are initialising JobService without giving it a IRepository argument, to get your code to compile you need to define a constructor in JobService that does not have an IRepository argument if you want to do that:
public class JobService
{
private readonly IRepository _repository;
// New Constructor will make _repository null
public JobService()
{
}
public JobService(IRepository repository)
{
_repository = repository;
}
public Job CreateJobBanker()
{
var banker = new Job();
string id = Guid.NewGuid().ToString("N");
Console.WriteLine("Novo job banker id: {0}", id);
banker.Id = id;
banker.Type = JobType.Banker;
banker.CreatedAt = DateTime.Now;
Console.WriteLine("Salvando job banker id: {0}", id);
// NullReferenceException if you define a parameterless constructor
Job jobBanker = _repository.SaveJob(banker);
return jobBanker;
}
}
Now you can construct it in two ways:
var jobService = new JobService();
or
var jobService = new JobService(new Repository());
IRepository implementation:
public class Repository: IRepository
{
private MyDbEntities context = new MyDbEntities();
public Job SaveJob(Job job)
{
// assuming Entity Framework
var id = job.Id;
if (context.Jobs.Any(e => e.Id == id))
{
context.Jobs.Attach(job);
context.ObjectStateManager.ChangeObjectState(jobs, EntityState.Modified);
}
else
{
context.Jobs.AddObject(myEntity);
}
context.SaveChanges();
return job;
}
}