I've got a base ApiController for my controllers to inherit:
public BaseApiController(ILogger logger) : ApiController
{
private readonly ILogger _logger;
public BaseApiController(ILogger logger)
{
_logger = logger.ForContext("SomeContext");
}
}
And a simple controller that's inheriting from the base controller:
public SomeController : BaseApiController
{
public SomeController(ILogger logger) : base(logger)
{ }
public IHttpActionResult SomeAction()
{
_logger.Information("Start doing something...");
//Do stuff...
_logger.Information("End doing something...");
return Ok();
}
}
I've created a simple test for the controller using Xunit and Nsubstitute:
public void SomeAction_ReturnsOk()
{
//Arrange
var logger = Substitute.For<ILogger>();
var controller = new SomeController(logger) {
Request = Substitute.For<HttpRequestMessage>()
};
//Act
var result = controller.SomeAction();
//Assert
logger.ReceivedWithAnyArgs().Information(Arg.Any<string>());
}
When executing the test case, it fails stating that it has received zero calls to the logger.Information() method. When debugging the _receivedCalls property (on the substituted ILogger), if the debug context is within the test case itself it is showing a single call to the logger.ForContext() method (which was called on the base class constructor), however when looking at the debug within the context of the controller.SomeAction() method, the same _receivedCalls property shows the two calls to logger.Information() as would be expected but not the call to ForContext().
So it appears to me that for some reason Nsubstitute is creating two separate instances of the substitute class, one in the context of the base controller and one in the actual controller - why is this and how can I avoid it?
You need to stub the ForContext return like this:
public void SomeAction_ReturnsOk()
{
//Arrange
var logger = Substitute.For<ILogger>();
logger.ForContext(Arg.Any<string>()).Returns(logger);
var controller = new SomeController(logger) {
Request = Substitute.For<HttpRequestMessage>()
};
//Act
var result = controller.SomeAction();
//Assert
logger.Received().Information(Arg.Any<string>());
}
I change the assert to:
logger.Received().Information(Arg.Any<string>());
OR:
logger.ReceivedWithAnyArgs().Information("");
Related
I have the following setup:
A calendar controller that calls a calendar service that calls a calendar client wrapper that calls the client. Controller -> Service -> ClientWrapper -> Client.
I am making an integration test that mocks the lowest tier (the client) and calls the controller to see if the client was called correctly.
My CalendarControllerBuilder:
internal class CalendarControllerBuilder
{
public CalendarControllerBuilder()
{
CalendarClientMock = new Mock<ICalendarServiceClient>(MockBehavior.Strict);
}
public Mock<ICalendarServiceClient> CalendarClientMock { get; set; }
public CalendarControllerBuilder With(Mock<ICalendarServiceClient> calendarClientWrapperMock)
{
CalendarClientMock = calendarClientWrapperMock;
return this;
}
public CalendarController Create()
{
var calendarClientWrapperMock = new CalendarClientWrapper(CalendarClientMock.Object);
var calenderService = new CalendarService(calendarClientWrapperMock);
return new CalendarController(calenderService);
}
}
Test setup with customization registration:
internal class CalenderControllerCustomization : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Register<CalendarController>(() =>
{
// ----- ICalendarServiceClient mock setups -----
var calendarServiceClientMock = new Mock<ICalendarServiceClient>(MockBehavior.Strict);
calendarServiceClientMock.Setup(m => m.GetEvents(It.IsAny<DateTime>(), It.IsAny<DateTime>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(fixture.Create<EventList>()).Verifiable();
return new CalendarControllerBuilder()
.With(calendarServiceClientMock)
.Create();
});
}
}
My automoq data attribute (using AutoFixture.Xunit2):
public class Attributes
{
public class AutoMoqDataAttribute<T> : AutoDataAttribute where T : ICustomization, new()
{
public AutoMoqDataAttribute()
: base(() => new Fixture()
.Customize(
new CompositeCustomization(
new AutoMoqCustomization(),
new T())))
{
}
}
public class AutoMoqDataAttribute : AutoDataAttribute
{
public AutoMoqDataAttribute()
: base(() => new Fixture()
.Customize(
new AutoMoqCustomization()))
{
}
}
}
My test that works fine and uses the customization registration:
[Theory]
[AutoMoqData<CalenderControllerCustomization>]
public async Task Test_GetAllEvents_ClientIsCalledCorrectlyAndReturnsCorrectData(
IFixture fixture,
[Frozen] Mock<ICalendarServiceClient> calendarServiceClientMock,
CalendarController sut)
{
// Arrange
var startDate = fixture.Create<DateTimeOffset>();
var endDate = fixture.Create<DateTimeOffset>();
// Act
var eventList = await sut.GetAllEvents(startDate, endDate);
// Assert
eventList.Events.Count.Should().Be(3); // fixture always create 3 of lists here
calendarServiceClientMock.Verify();
}
THE PROBLEM:
Now I want to override the setup with my own data returned.
[Theory]
[AutoMoqData<CalenderControllerCustomization>]
public async Task Test_GetAllEvents_ClientIsCalledCorrectlyAndReturnsCorrectData_Overridden(
IFixture fixture,
[Frozen] Mock<ICalendarServiceClient> calendarServiceClientMock,
CalendarController sut)
{
// Arrange
var startDate = fixture.Create<DateTimeOffset>();
var endDate = fixture.Create<DateTimeOffset>();
var result = fixture.Build<EventList>()
.With(x => x.Events, fixture.CreateMany<Event>(5).ToList())
.Create();
// override client mock setup:
calendarServiceClientMock.Setup(m => m.GetEvents(It.IsAny<DateTime>(), It.IsAny<DateTime>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(fixture.Build<EventList>()
.With(x => x.Events, fixture.CreateMany<Event>(5).ToList())
.Create()).Verifiable();
// Act
var eventList = await sut.GetAllEvents(startDate, endDate);
// Assert
eventList.Events.Count.Should().Be(5); // FAILS - IT GETS 3 AND NOT 5
calendarServiceClientMock.Verify(); // THIS FAILS TOO IF I SET 3 IN ABOVE
}
I have tried with and without the Frozen attribute.
What am I missing here? I don't want to call my calendarcontroller builder as the point is to avoid boilerplate. Do I need a registration of the client or something else I'm missing
(maybe related to Override Autofixture customization setup but using moq and not n-subtitute. Could not get this to work even with correct order of parameters)
Thanks for reading!
With the current way you customize the fixture I don't think you can. By creating a custom builder and instantiating the mock by hand you've basically painted yourself in a corner.
To get AutoFixture to control the instances you need in the test, you must allow it to generate them. Here's a possible solution.
The root of your SUT is the controller. Let's say it receives as a parameter an ICalendarService that's always the concrete implementation CalendarService.
To tell AutoFixture that the implementation is always a concrete type you can relay the resolved type to the concrete implementation.
fixture.Customizations.Add(new TypeRelay(typeof(ICalendarService), typeof(CalendarService)));
Next the service takes as a constructor parameter an abstraction that's ICalendarClient which is resolved as the wrapper but only for the service. This means you have to identify the constructor parameter and relay the request to the wrapper type.
fixture.Customizations.Add(new FilteringSpecimenBuilder(
new FixedRequestRelay(typeof(CalendarClientWrapper)),
new YourConstructorParameterSpecification()));
The YourConstructorParameterSpecification is a IRequestSpecification implementation that identifies a request as a parameter of type ICalendarClient that belongs to the constructor of type CalendarService.
FixedRequestRelay is a simple ISpecimenBuilder that always resolves the same predefined request from ISpecimenContext instead of the received one.
Here's a very basic implementation of it.
public record FixedRequestRelay(object Request) : ISpecimenBuilder
{
public object Create(object request, ISpecimenContext context)
=> context.Resolve(this.Request);
}
Next you have your wrapper that also takes as a parameter an abstraction of type ICustomerClient. However this instance you want to be resolved as a mock that you can control from the test. Since you use AutoFixure.AutoMoq you can leave this one as is and let AutoMoq generate a mock for it.
Let's say this is the resulting customization.
public class CalendarCustomization : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Customizations.Add(new TypeRelay(typeof(ICalendarService), typeof(CalendarService)));
fixture.Customizations.Add(new FilteringSpecimenBuilder(
new FixedRequestRelay(typeof(CalendarClientWrapper)),
new AndRequestSpecification(
new ParameterSpecification(typeof(ICalendarClient), "client"),
new ParameterMemberSpecification(
new DeclaringTypeSpecification(
new ExactTypeSpecification(typeof(CalendarService)))))));
}
}
By using it you can write a test like this.
[Theory, MyData]
public async Task Foo(
[MinLength(5)] Event[] events,
[Frozen] Mock<ICalendarClient> clientMock,
CalendarController controller,
DateTime start, DateTime end)
{
clientMock
.Setup(x => x.GetAllEvents(It.IsAny<DateTime>(), It.IsAny<DateTime>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(events);
var actual = await controller.GetAllEvents(start, end, default);
Assert.Equal(events, actual);
}
I'm developing a unit test using xUnit I'am having a syntax problem on creating an instance of my service layers in my test method it shows the following message error
There is no argument given that corresponds to the required formal parameter 'mapper' of 'MunicipioAppService.MunicipioAppService
I've tried putting mapper into the parameters but didn't work
How I'm creating the instance
[Fact]
public async Task SearchState_ObterPorId_RetornarComSucesso()
{
//Arrange
var mockStateRepo = new MockStateRepository()
.MockGetByID(new State());
var stateService = new StateAppService(mockStateRepo); //Error
//Act
var result = StateService.ObterPorID(54);
}
My AppService Class
public class StateAppService : AppService<StateViewModel, IStateRepository, State>, IStateAppService
{
public StateAppService(IStateRepository repository, IMapper mapper, INotificationHandler notificationHandler)
: base(notificationHandler)
{
SetRepository(repository);
SetMapper(mapper);
}
public IEnumerable<StateViewModel> ObterPorID(long stateId)
{
return Mapper.Map<IEnumerable<StateViewModel>>(Repository.ObterPorID(stateId));
}
}
So I am very new to writing tests. I created an ASP.NET core web api along with angular. I have to write unit tests for the web API controllers. I have been reading Microsoft documentation on how to get started with unit tests of ASP.NET web APIs. But I am still very unsure on how to go about writing proper tests.
My Controller Code
[Authorize]
[Route("api/[controller]")]
[ApiController]
public class OrdersController : ControllerBase
{
private readonly IOrderRepository _repo;
private readonly IMapper _mapper;
public OrdersController(IOrderRepository repo, IMapper mapper)
{
_repo = repo;
_mapper = mapper;
}
[AllowAnonymous]
[HttpPost()]
public async Task<IActionResult> AddOrder(OrderForMappingDto orderForMappingDto)
{
//if(orderForMappingDto.ARentalOrNot == null)
//{
// throw new Exception("Value can't be left null");
//}
var orderToCreate = _mapper.Map<TblOrder>(orderForMappingDto);
var createdOrder = await _repo.AddOrder(orderToCreate);
return Ok(createdOrder);
}
}
My Repository Code
public class OrderRepository : IOrderRepository
{
private readonly MovieRentalDBContext _context;
public OrderRepository(MovieRentalDBContext context)
{
_context = context;
}
public async Task<TblOrder> AddOrder(TblOrder tblOrder)
{
await _context.TblOrder.AddAsync(tblOrder);
await _context.SaveChangesAsync();
return tblOrder;
}
}
I understand there is a lot of mocking to be done. But do I need to mock the Entity Framework as well?
I wrote a simple test file.
public void PostsAorder_WhenCalled_ReturnsOkWithResponse()
{
var mockOrderRepository = new Mock<IOrderRepository>();
var mockOrderMapper = new Mock<IMapper>();
var orderControllerObject = new OrdersController(mockOrderRepository.Object, mockOrderMapper.Object);
Task<IActionResult> contentResult = orderControllerObject.AddOrder(new OrderForMappingDto
{
ACustomerId = 3,
AMovieId = 18,
ARentalOrNot = false,
AOrderedDate = DateTime.Now
}) ;
//var contentResult = actionResult as OkNegotiatedContentResult<OrderForMappingDto>;
Assert.IsNotNull(contentResult);
Assert.IsNotNull(contentResult.Result);
}
The OkNegotioatedContent function doesn't work with Tasks. How do I go about using that for task. Also, the tests is passing even when I don't supply the last 3 arguments even though in the DTO they are classified as [Required]. Can somebody help on how to modify the test properly.
mapper Configuration-
Your test is almost okay. First the fixed version then some explanation:
[Fact]
public async Task GivenAValidOrder_WhenICallTheAsOrder_ThenItReturnsOkWithResponse()
{
//Arrange
var mockOrderMapper = new Mock<IMapper>();
mockOrderMapper.Setup(mapper => mapper.Map<TblOrder>(It.IsAny<OrderForMappingDto>()))
.Returns(new TblOrder());
var mockOrderRepository = new Mock<IOrderRepository>();
mockOrderRepository.Setup(repo => repo.AddOrder(It.IsAny<TblOrder>()))
.ReturnsAsync((TblOrder order) => order);
var SUT = new OrdersController(mockOrderRepository.Object, mockOrderMapper.Object);
//Act
var contentResult = await SUT.AddOrder(new OrderForMappingDto
{
ACustomerId = 3,
AMovieId = 18,
ARentalOrNot = false,
AOrderedDate = DateTime.Now
});
//Assert
Assert.NotNull(contentResult);
Assert.IsAssignableFrom<OkObjectResult>(contentResult);
var result = ((OkObjectResult)contentResult).Value;
Assert.NotNull(result);
Assert.IsAssignableFrom<TblOrder>(result);
}
The name of test follows the Given When Then structure to make it easier to understand that under what circumstances how should the controller's action behave.
The test is now asynchronous because we need to await the controller's action to finish in order to examine its result.
I've added the Arrange Act Assert comments to the code in order to emphasize which phase starts when.
I've set the mapper mock to return a new TblOrder and the repo mock to return whatever it receives.
I've renamed orderControllerObject to SUT, because it emphasize which component is under examination (System Under Test).
In the result verification I've used IsAssingableForm instead of IsType because it checks against derived classes as well. In this particular case it is not mandatory, but it is a good practice.
The result type will be OkObjectResult not OkNegotiatedContentResult, so you should check against that.
And finally I've added an extra check to make sure that the returned object's type is that what is expected.
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);
}
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));
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);
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.
I have a simple contoller of a standard MVC 5 web application. I installed the MVC 5 Ninject nuget package. I created a constructor and the interface that I have defined is injected. If I create a public property this is also injected.
Now when I create a unittest project and want to test the mvc controller. How can I do that? I have to create a kernel. The kernel is created and if I get an instance of my IPersonComponent it is created. But why doesn't my property not get injected?
I created two options and both I get nullreference exception...
Interface:
public interface IPersonComponent
{
void DoSomething();
}
Implementation:
public class PersonComponent : IPersonComponent
{ public void DoSomething()
{
throw new NotImplementedException("The method is fired but not implemented");
}
}
TestInitialize:
private IKernel _kernel;
[TestInitialize()]
public void Initialize()
{
_kernel = new StandardKernel();
}
Option 1
Controller that is working great:
public class HomeController : Controller
{
private readonly IPersonComponent _component;
public HomeController(IPersonComponent component)
{
_component = component;
}
}
Unittest fails because PersonComponent is null:
[TestClass]
public class HomeControllerTest
{
[Inject]
public IPersonComponent PersonComponent { get; set; }
[TestMethod]
[ExpectedException(typeof(NotImplementedException))]
public void Index()
{
// Arrange
HomeController controller = new HomeController(PersonComponent);
// Act
ViewResult result = controller.Index() as ViewResult;
// Assert
Assert.IsNotNull(result);
}
}
Option 2
Controller:
public class HomeController : Controller
{
[Inject]
public IPersonComponent PersonComponent { get; set; }
public HomeController()
{
}
public ActionResult Index()
{
PersonComponent.DoSomething();
return View();
}
}
Test:
[TestMethod]
[ExpectedException(typeof(NotImplementedException))]
public void Index()
{
// Arrange
HomeController controller = new HomeController();
// Act
ViewResult result = controller.Index() as ViewResult;
// Assert
Assert.IsNotNull(result);
}
This works:
But why does it work? Why isn't it injected automatically?
[TestMethod]
public void TestDoSomething()
{
var kernel = new StandardKernel();
var comp = kernel.Get<IPersonComponent>();
comp.DoSomething();
}
Edit based on the answer:
Option 1
[TestMethod]
[ExpectedException(typeof(NotImplementedException))]
public void Index()
{
_kernel.Inject(this);
// Arrange
HomeController controller = new HomeController(PersonComponent);
// Act
ViewResult result = controller.Index() as ViewResult;
// Assert
Assert.IsNotNull(result);
}
Option 2
[TestMethod]
[ExpectedException(typeof(NotImplementedException))]
public void Index()
{
// Arrange
HomeController controller = _kernel.Get<HomeController>();
// Act
ViewResult result = controller.Index() as ViewResult;
// Assert
Assert.IsNotNull(result);
}
In option 1: MsTest does not invoke Ninject to tell it to inject services into your objects.
In option 2: You are creating the controller manually (new HomeController()), and you're not telling Ninject to inject services into your objects.
Although much of what Ninject does seems "magical," it still has to be invoked in order to be able to inject values into your components. ASP.NET MVC has a mechanism that Ninject ties itself into, so that construction of controllers is handled by Ninject automatically. This gives you the impression that Ninject is able to inject values into anything without effort. But MSTest does not have a similar mechanism, so you have to do some of this work manually.
If you have access to the ninject kernel that's been configured, you can say:
HomeController controller = kernel.Get<HomeController>();
Or, in option 1, you can say:
public HomeControllerTest()
{
kernel.Inject(this); // populate my [Inject] properties
}
I should mention that if you're injecting dependencies based on real bindings, you're not really writing "unit tests," but rather "automated acceptance tests." If you want to test the behavior of a controller action independent of its dependencies, learn how to "mock" its dependencies instead.