I am using xunit with Moq and testing other functionality in one function but i always get an exception from Fluent Validation extension methods which I can not bypass.
This is original code
public class AdService : IAdService
{
private readonly IValidator<AdToSearchDto> _adToSearchDtoValidator;
public AdService(IValidator<AdToSearchDto> addToSearchDtoValidator)
{
_adToSearchDtoValidator = addToSearchDtoValidator
}
public async Task<AdsToReturnDto> GetAdsAsync(AdToSearchDto searchDto)
{
_adToSearchDtoValidator.ValidateAndThrow(searchDto); // This line always throw exception
return await _adRepository.GetUserAdsAsync(searchDto, userId, user?.Country);
}
}
Unit test class
[Fact]
public async Task Ads_Can_Searched_By_UserId()
{
var validator = new Mock<IValidator<AdToSearchDto>>();
var adService = new AdService(validator.Object);
var adService = new AdService(validator.Object );
var ads = DataGenerator.CreateAds(2);
ads[0].UserId = searchingUserId;
ads[1].UserId = anotherUserId;
await adRepository.CreateAdAsync(ads[0]);
await adRepository.CreateAdAsync(ads[1]);
var result = await adService.GetAdsAsync( adToSearchDto, Guid.Empty ) ;
result.Ads.Count.Should().Be(1);
result.Ads.FirstOrDefault()?.UserId.Should().Be(searchingUserId.ToString());
}
I cant bypass
ValidateAndThrow
as this is extension method.
Is there any way to bypass ValidateAndThrow method in unit test ?
Edited:
Error i am getting
System.NullReferenceException : Object reference not set to an instance of an object.
at FluentValidation.DefaultValidatorExtensions.ValidateAndThrow[T](IValidator`1 validator, T instance, String ruleSet) in C:\Projects\FluentValidation\src\FluentValidation\DefaultValidatorExtensions.cs:line 943
at Market.Business.Ad.AdService.GetAdsAsync(AdToSearchDto searchDto, Guid userId) in C:\Users\Shahid Abdullah\Projects\MyStuff.IdentityServer\src\Market\Market.Business\Ad\AdService.cs:line 129
at Market.Test.Ad.AdTests.Ads_Can_Searched_By_UserId() in C:\Users\Shahid Abdullah\Projects\MyStuff.IdentityServer\src\Market\Market.Test\Ad\AdTests.cs:line 100
--- End of stack trace from previous location where exception was thrown ---
Exception in source code
public static void ValidateAndThrow<T>(
this IValidator<T> validator,
T instance,
string ruleSet = null)
{
ValidationResult validationResult = validator.Validate<T>(instance, (IValidatorSelector) null, ruleSet);
if (!validationResult.IsValid) // this line throws exception as validationResult is null
throw new ValidationException((IEnumerable<ValidationFailure>) validationResult.Errors);
}
/// <summary>
/// Performs validation and then throws an exception if validation fails.
/// </summary>
/// <param name="validator">The validator this method is extending.</param>
/// <param name="instance">The instance of the type we are validating.</param>
/// <param name="ruleSet">Optional: a ruleset when need to validate against.</param>
public static void ValidateAndThrow<T>(this IValidator<T> validator, T instance, string ruleSet = null) {
var result = validator.Validate(instance, ruleSet: ruleSet);
if (!result.IsValid) {
throw new ValidationException(result.Errors);
}
}
Source
ValidateAndThrow expects a result to be return from the validator when invoked.
Because there is no result from the mock
if (!result.IsValid) {...
throws a null reference exception.
Setup the mock to behave as expected when the extension method is invoked while exercising the test
[Fact]
public async Task Ads_Can_Searched_By_UserId() {
//Arrange
var validator = new Mock<IValidator<AdToSearchDto>>();
var validResult = new ValidationResult();
validator
.Setup(_ => _.Validate(It.IsAny<ValidationContext>())
.Returns(validResult);
var adService = new AdService(validator.Object);
//...
}
Related
This question already has answers here:
Mock lazy interface with Moq
(3 answers)
Closed 1 year ago.
The system under test
public class AddDateRangeSaga : IDistributedSaga<AddDateRangeRequestModel, AddDateRangeResponseModel>
{
/// <summary>
/// AddDateRangeAr Inject
/// </summary>
public readonly Lazy<IAddDateRangeAr> _addDateRangesAr;
/// <summary>
/// For log and exception handling
/// </summary>
private readonly IApiRequestHandler _reqHandler;
public AddDateRangeSaga(IApiRequestHandler reqHandler
, Lazy<IAddDateRangeAr> addDateRangesAr)
{
_reqHandler = reqHandler;
_addDateRangesAr = addDateRangesAr;
}
public async Task<AddDateRangeResponseModel> Execute(AddDateRangeRequestModel request)
{
return await _addDateRangesAr.Value.AddDateRange(request);
}
}
The test case
public class AddDateRangeSagaTests
{
private Mock<IApiRequestHandler> _mockApiRequestHandler;
public Mock<Lazy<IAddDateRangeAr>> _addDateRangesAr;
private MockRepository mockRepository;
[SetUp]
public void SetUp()
{
mockRepository = new MockRepository(MockBehavior.Strict);
_mockApiRequestHandler = mockRepository.Create<IApiRequestHandler>();
_addDateRangesAr = mockRepository.Create<Lazy<IAddDateRangeAr>>();
}
private AddDateRangeSaga CreateAddDateRangeSagaTests()
{
return new AddDateRangeSaga(this._mockApiRequestHandler.Object, _addDateRangesAr.Object);
}
[Test]
public async Task AddDateRangeSaga_StateUnderTest_ExpectedBehavior()
{
//Arrange
var addDateRangeAr = this.CreateAddDateRangeSagaTests();
AddDateRangeRequestModel addDateRangeRequestModel = new AddDateRangeRequestModel();
AddDateRangeResponseModel addDateRangeResponseModel = new AddDateRangeResponseModel();
_addDateRangesAr.Setup(x => x.Value.AddDateRange(addDateRangeRequestModel)).ReturnsAsync(addDateRangeResponseModel);
var dd = addDateRangeAr.Execute(addDateRangeRequestModel);
//Assert
Assert.AreEqual(1,1); //dummy
}
}
Received error during execution
System.NotSupportedException : Unsupported expression: x => x.Value
Non-overridable members (here: Lazy.get_Value) may not be used in setup / verification expressions.
Problem
I am not able to figure out the exact issue with lazy moq. Can someone help me to figure out the issue?
First let me share with you the revised version of your test then the explanation.
public class AddDateRangeSagaTests
{
private Mock<IApiRequestHandler> apiRequestHandlerMock;
private Mock<IAddDateRangeAr> addDateRangesArMock;
private MockRepository mockRepository;
[SetUp]
public void SetUp()
{
mockRepository = new MockRepository(MockBehavior.Strict);
apiRequestHandlerMock = mockRepository.Create<IApiRequestHandler>();
addDateRangesArMock = mockRepository.Create<IAddDateRangeAr>();
}
private AddDateRangeSaga CreateAddDateRangeSagaTests()
{
var lazyAddDateRangesAr = new Lazy<IAddDateRangeAr>(() => addDateRangesArMock.Object);
return new AddDateRangeSaga(apiRequestHandlerMock.Object, lazyAddDateRangesAr);
}
[Test]
public async Task AddDateRangeSaga_StateUnderTest_ExpectedBehavior()
{
//Arrange
var sut = this.CreateAddDateRangeSagaTests();
addDateRangesArMock
.Setup(x => x.AddDateRange(It.IsAny<AddDateRangeRequestModel>()))
.ReturnsAsync(new AddDateRangeResponseModel());
//Act
var response = await sut.Execute(addDateRangeRequestModel);
//Assert
Assert.NotNull(response);
}
}
I've changed your _addDateRangesAr field to addDateRangesArMock
Here we are mocking the interface itself not the Lazy container
I've changed the visibility as well from public to private because this field should not be accessed by any other class
I've changed the name of _mockApiRequestHandler field to apiRequestHandlerMock to avoid using _ prefixes
Inside the CreateAddDateRangeSagaTests I've initialized a Lazy<IAddDateRangeAr> which will return the mocked IAddDateRangeAr whenever it's first accessed
I've simplified the mock setup and made it more generic
from .AddDateRange(addDateRangeRequestModel)
to .AddDateRange(It.IsAny<AddDateRangeRequestModel>())
I've called the Execute with await to be able to examine the response
I've used a simple null check to make sure it works as expected
We are creating unit tests for an application and ran into a problem creating certain tests.
We are unit testing the following Handle() method of the class ActivateCommandHandler:
public class ActivateCommand : IRequest<HttpResponseMessage>
{
public string Controller { get; set; }
public ActivateCommand(string controllername)
{
this.Controller = controllername;
}
}
public class ActivateCommandHandler : CommandHandler<ActivateCommand, HttpResponseMessage>
{
protected readonly ICommandsGateway _commandsGateway;
protected readonly EndpointSettings _endpoints;
protected readonly IUserProfile _userprofile;
public ActivateCommandHandler(IMediator mediator, ICommandsGateway commandsGateway, IOptions<EndpointSettings> endpoints, IValidationContext validationContext, IUserProfile currentUser) : base(mediator, validationContext, currentUser)
{
_commandsGateway = commandsGateway;
_endpoints = endpoints.Value;
_userprofile = currentUser;
}
public override async Task<HttpResponseMessage> Handle(ActivateCommand command, CancellationToken cancellationToken)
{
if (_endpoints.EndpointExists(command.Controller))
{
// Check whether the second server controller is deactivated
string peercontroller = _endpoints.GetPeerController(command.Controller);
if (!string.IsNullOrEmpty(peercontroller))
{
BaseRedundancySwitchStatus controllerStatus = await _commandsGateway.GetRedundancySwitchStatus(_endpoints.GetEndpointAddress(peercontroller));
if ((controllerStatus.CurrentState == "Activated") || (controllerStatus.CurrentState == "ActivatedWithWarning") || (controllerStatus.CurrentState == "Activating"))
{
var resp = new HttpResponseMessage(HttpStatusCode.Conflict)
{
Content = new StringContent($"{peercontroller},{controllerStatus.CurrentState}")
};
return resp;
}
}
var result = await _commandsGateway.PostActivateCommand(_endpoints.GetEndpointAddress(command.Controller));
return result;
}
else
{
throw new InvalidControllerNameException($"ERROR: The controller {command.Controller} does not exist as an endpoint on this Control Center!");
}
}
}
For this the following were mocked: _endpoints, command and _commandsGateway (interface). This works great for unit testing the parameter validation. But we now want to test the behaviour when the peercontroller status is set to a specific value.
To do this we are trying to mock out the function _commandsGateway.GetRedundancySwitchStatus(). The following is the actual test implementation. We mock the _commandsGateway.GetRedundancySwitchStatus() function to return the expected BaseRedundancySwitchStatus with CurrentState set to "Activated". After that we call the handler of the actual function to be tested and check whether we get the expected error.
[Fact]
public async void ShouldHaveErrors_PeerControllerStateActivated()
{
var command = new ActivateCommand("Server Controller Slave1");
BaseRedundancySwitchStatus result = new BaseRedundancySwitchStatus()
{
CurrentState = "Activated"
};
_commandsGateway
.Setup(s => s.GetRedundancySwitchStatus("Server Controller Slave1"))
.ReturnsAsync(result);
HttpResponseMessage res = await _handler.Handle(command, CancellationToken.None);
Assert.True(res.StatusCode == System.Net.HttpStatusCode.Conflict);
}
Debugging the code, when I step through the code in the Handle() method where _commandsGateway.GetRedundancySwitchStatus is called, I can see that _endpoints.GetEndpointAddress(command.Controller) (which is the parameter) is called and the correct value is returned. After this the debugger steps to the next line without any indication of having executed the mock GetRedundancySwitchStatus() function. Inspecting the controllerStatus variable the value is null. I would expect the value to be the BaseRedundancySwitchStatus object which is supposed to be returned by the mocked GetRedundancySwitchStatus() function.
Where are we going wrong?
I'm working on a small unit test for a simple asp.net core middleware and trying to work out if it's possible to get 100% coverage on this very basic scenario. I'm using Visual Studio 2017 > "Analyze Code Coverage", xUnit and Moq for completeness. On my async methods (one illustrated below) code analysis is reporting only partial coverage. Is there a way to get these fully covered?
// Sample Middleware
internal sealed partial class JsonExceptionMiddleware
{
private const string DefaultErrorMessage = "A server error occurred.";
private readonly RequestDelegate _next;
private readonly ILogger<JsonExceptionMiddleware> _logger;
public JsonExceptionMiddleware(RequestDelegate next, ILoggerFactory loggerFactory, IHostingEnvironment hostingEnvironment)
{
_next = next ?? throw new ArgumentNullException(nameof(next));
_logger = loggerFactory?.CreateLogger<JsonExceptionMiddleware>() ?? throw new ArgumentNullException(nameof(loggerFactory));
IncludeExceptionMessage = hostingEnvironment.IsDevelopment();
IncludeExceptionStackTrace = hostingEnvironment.IsDevelopment();
}
/// <summary>
/// Gets or sets whether the <see cref="Exception.StackTrace"/> should be included in the response message.
/// </summary>
public bool IncludeExceptionStackTrace { get; set; }
/// <summary>
/// Gets or sets whether the <see cref="Exception.Message"/> should be included in the response message.
/// </summary>
public bool IncludeExceptionMessage { get; set; }
/// <summary>
/// Implements the <see cref="RequestDelegate"/> so this class can be used as middleware.
/// </summary>
/// <param name="context">The current <see cref="HttpContext"/>.</param>
/// <returns>A <see cref="Task"/> that completes when the error message is flush to the HTTP response.</returns>
public async Task Invoke(HttpContext context)
{
try
{
await _next(context);
}
catch (Exception ex)
{
if (context.Response.HasStarted) throw;
context.Response.Clear();
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
context.Response.ContentType = ApiConstants.Http.JsonContentType;
ApiError error = BuildError(ex);
await context.Response.WriteAsync(JsonConvert.SerializeObject(error, new JsonSerializerSettings(){ NullValueHandling = NullValueHandling.Ignore}));
}
}
private ApiError BuildError(Exception ex)
{
string message = DefaultErrorMessage;
string detail = null;
string stack = null;
if (IncludeExceptionMessage)
detail = ex.Message;
if (IncludeExceptionStackTrace)
stack = ex.StackTrace;
var error = new ApiError(message, detail, stack);
return error;
}
}
Blue=covered, Yellow=partially covered, Red=not covered
// Sample Unit Test
[Fact]
public async Task SampleUnit()
{
// arrange
var environment = new Mock<IHostingEnvironment>();
environment
.SetupGet(x => x.EnvironmentName)
.Returns(EnvironmentName.Development);
var response = new Mock<HttpResponse>();
response
.Setup(x => x.HasStarted)
.Returns(true);
var httpContext = new Mock<HttpContext>();
httpContext
.SetupGet(x => x.Response)
.Returns(response.Object);
var loggerFactory = new Mock<LoggerFactory>();
var jsonExceptionMiddleware = new JsonExceptionMiddleware((innerHttpContext) => throw new Exception(SampleExceptionDetail), loggerFactory.Object, environment.Object);
// act & assert
await Assert.ThrowsAsync<Exception>(async () => await jsonExceptionMiddleware.Invoke(httpContext.Object).ConfigureAwait(false));
}
From the looks of the covered code, the test(s) throw on the await and only flows through the catch block.
Allow the await to flow to completion by not throwing an exception in the request delegate. Using the sample test provided, you would need to initialize the middleware like this
//...
var jsonExceptionMiddleware = new JsonExceptionMiddleware((context) => Task.CompletedTask,
loggerFactory.Object, environment.Object);
//...
For the other uncovered code, you just have to make sure an error is thrown on the await like it is now, but make sure that context.Response.HasStarted is true.
I am trying to build a FilterAttribute that will handle my errors for my Web API. Currently it logs the errors to the database, but it always returns a 500 Internal Server error no matter what I do.
My filter looks like this:
public class LogExceptionFilterAttribute : ExceptionFilterAttribute
{
// Private properties
private readonly ILogProvider _logger;
/// <summary>
/// Our default constructor
/// </summary>
/// <param name="logger"></param>
public LogExceptionFilterAttribute(ILogProvider logger)
{
_logger = logger;
}
/// <summary>
/// Invoked when an exception has been thrown
/// </summary>
/// <param name="context">The context</param>
public override async void OnException(HttpActionExecutedContext context)
{
// Get our user
var requestContext = context.Request.GetRequestContext();
var user = requestContext.Principal.Identity;
// Create our response
var message = await _logger.ErrorAsync(context.Exception, user);
var statusCode = GetStatusCodeFromException(context);
var content = new HttpResponseMessage(statusCode);
//{
// Content = new StringContent(message),
// StatusCode = statusCode
//};
// Assign our response to our context
context.Response = content;
}
/// <summary>
/// Gets a status code from an error
/// </summary>
/// <param name="context">The context</param>
/// <returns></returns>
private static HttpStatusCode GetStatusCodeFromException(HttpActionExecutedContext context)
{
// Cast the exception as an HttpException
var exception = context.Exception as HttpException;
// If there is still an exception, return the code
if (exception != null)
return (HttpStatusCode)exception.GetHttpCode();
// Switch on the exception type
switch (context.Exception)
{
// Not found
case ObjectNotFoundException ex:
return HttpStatusCode.NotFound;
// Not implemented
case NotImplementedException ex:
return HttpStatusCode.NotImplemented;
// Internal server error
default:
return HttpStatusCode.InternalServerError;
}
}
}
I have put a breakpoint in the GetStatusCodeFromException method and verified that the actual status code I should be getting is 501 (Not Implemented) but the return is always 500. I have tried with other status codes too and it is always a 500.
Does someone know how I can actually get it to return a different status code?
Update
I have found out more.
If I change my OnException method to this:
public override async void OnException(HttpActionExecutedContext context)
{
// Get our user
var request = context.Request;
//var requestContext = request.GetRequestContext();
//var user = requestContext.Principal.Identity;
//// Log our error and get the status code
//var message = await _logger.ErrorAsync(context.Exception, user);
//var statusCode = GetStatusCodeFromException(context);
// Create our response
context.Response = request.CreateResponse(HttpStatusCode.NotImplemented);
}
I get a nice 501 error when using postman, but as soon as I uncomment the requestContext line, it get an error 500. I think that invoking GetRequestContext somehow changes the HttpRequestMessage so that when I invoke CreateResponse it always generates a 500.
Anyone know why? Or how to get around it?
I am writing test for CheckPassWord()
I presume the Expect call is not behaving as expected on my userMangerMock.
//CheckPassword returns true if the parameter matches to the exsting user.
//Existing user is obtained by GetUser() by internal call
bool passWordMatch = userMangerMock.CheckPassword(userInfo.Id, userInfo.Password);
CheckPassWord() internally calls GetUser(),
Since GetUser() needs more deeper internal calls I decided to return a stubUser
I believe implementation of Expect() is sufficient for that.
Note that the following call var userInfo = userMangerMock.GetUser("TestManager");is returning stubUser.
But , CheckPassword() call I am assuming the stubUser is not returned thus the test failing.
Correct me if any bug in the following UT.
//Use TestInitialize to run code before running each test
[TestInitialize()]
public void MyTestInitialize()
{
CreateUser();
}
private static IUser _stubUser;
public void CreateUser()
{
IUserFactory iUserFactory = new UserFactory();
UserParams parameters = new UserParams();
parameters.Password = "TestPassword123!";
parameters.UserID = "TestManager";
_stubUser = iUserFactory.CreateUser(parameters);
}
/// <summary>
///A test for CheckPassword
///</summary>
[TestMethod( )]
public void CheckPasswordTest()
{
// !!! Below I've used WhenCalled() to show you that correct
// expectation is called based on argument type, just see in debugger
IUserManager userMangerMock = MockRepository.GenerateMock<IUserManager>();
userMangerMock.Expect(x => x.GetUser(Arg<string>.Is.Anything))
.WhenCalled((mi) =>
{
Debug.WriteLine("IUserManager - string parameter");
})
.Return(_stubUser);
var userInfo = userMangerMock.GetUser("TestManager");
bool passWordMatch = userMangerMock.CheckPassword(userInfo.Id, userInfo.Password);
userMangerMock.VerifyAllExpectations();
Assert.AreEqual(true, passWordMatch);
}
/// <summary>
/// Returns true if password matches the user
/// </summary>
public bool CheckPassword(string userId, string password)
{
if (userId == null)
{
throw new ArgumentNullException("userId");
}
IUser user = GetUser(userId);
if (user == null)
{
throw new UserManagementException(UserManagementError.InvalidUserId);
}
return (user.Password == password);
}
A couple of things I noticed in your test:
userMangerMock.VerifyAllExpectations();
This will always pass since you are manually calling GetUser() in the test code itself:
var userInfo = userMangerMock.GetUser("TestManager");
So you can actually remove this verify call, since it's not needed.
It feels like your unit test does not seem to provide any value to you, since it's asserting on a hard-coded mock object.
var userInfo = userMangerMock.GetUser("TestManager");
bool passWordMatch = userMangerMock.ChePassword(userInfo.Id, userInfo.Password);
Assert.AreEqual(true, passWordMatch);
If userInfo is a reference to the stub object _stubUser then you're unit test can be refactored to:
bool passWordMatch = userMangerMock.CheckPassword(_stubUser.Id, _stubUser.Password);
Assert.AreEqual(true, passWordMatch);