I'm doing some unit testing using FluentValidation in Asp.net. I have setup a rule stating that an object is not allowed to be null, as it's going to be used as an argument in a method. The rule is made in a validator-class in the constructor:
//Object itself.
RuleFor(x => x).NotNull();
The unit test looks like (I'm using NUnit):
[Test]
public void RequestObjectIsNull_ExpectError()
{
BusinessRequest request = null;
var result = validator.Validate(request);
Assert.IsFalse(result.IsValid);
}
It fails with the message:
Message: System.ArgumentNullException : Cannot pass null model to Validate.
Parameter name: instanceToValidate
How do I test this?
This question is quite old but I have stumbled upon the same issue. I wanted the fluent validator to validate it for me if it is null and say so and not throw an exception, instead of me explicitly checking for it. I have found a solution of overriding the existing methods, For example:
public class MyValidator : AbstractValidator<MyObject>
{
public MyValidator()
{
RuleSet("MyRule", () =>
{
RuleFor(x=>x.MyProperty=="Something").WithMessage("failed");
});
}
public override Task<ValidationResult> ValidateAsync(ValidationContext<MyObjec>> context, CancellationToken cancellation = default)
{
return context.InstanceToValidate == null ? Task.FromResult(new ValidationResult(new[] { new ValidationFailure("MyObject", "filed with null") })) : base.ValidateAsync(context, cancellation);
}
}
Related
I'm relatively new to ReactiveUI and I'm trying to asynchronously execute a database query from a ReactiveCommand. From what I can tell, the problem isn't with executing the async query, but when I try to load the results into a ReactiveList in my view model. I believe that this is a scheduling issue but I'm not familiar enough with RxUI to come up with the correct approach.
I've tried subscribing to the command in the view model using ObserveOn with both RxApp.TaskPoolScheduler and RxApp.MainThreadScheduler but neither seems to help.
My view model:
public class UsersViewModel : ReactiveObject, IRoutableViewModel
{
ReactiveList<LisUser> _users;
IUserManagementService UsersService { get; }
public IScreen HostScreen { get; }
public ReactiveCommand<Unit, IEnumerable<LisUser>> LoadUsers { get; }
public String UrlPathSegment => "users";
public ReactiveList<LisUser> Users
{
get => _users;
set => this.RaiseAndSetIfChanged(ref _users, value);
}
public UsersSubPageViewModel(
IScreen screen,
IUserManagementService usersService)
{
HostScreen = screen ?? throw new ArgumentNullException(nameof(screen));
UsersService =
usersService ?? throw new ArgumentNullException(nameof(usersService));
Users = new ReactiveList<LisUser>();
LoadUsers = ReactiveCommand.CreateFromTask(async () =>
{
return await UsersService.GetUsersAsync().ConfigureAwait(false);
});
LoadUsers
.ObserveOn(RxApp.MainThreadScheduler)
.Subscribe(list =>
{
Users.Clear();
foreach (var u in list)
{
Users.Add(u);
}
});
}
}
My view:
public partial class UsersView : ReactiveUserControl<UsersViewModel>
{
public UsersPageView()
{
InitializeComponent();
this.WhenActivated(disposables =>
{
this.WhenAnyValue(x => x.ViewModel.LoadUsers)
.SelectMany(x => x.Execute())
.Subscribe()
.DisposeWith(disposables);
});
}
}
What I want to occur is when the UsersView is activated, the GetUsers method of the UsersService executes asynchronously and loads the returned list of users into the Users ReactiveList. Instead, I see a new tab in VS with a title of "Source Not Found" and a message saying that "RxApp.cs not found". The actual exception is a System.Exception with a message stating "Cannot obtain value of the local variable or argument because it is not available at this instruction pointer, possibly because it has been optimized away."
So, my first question is "is this actually a scheduling issue?" And the second question is "how do I resolve it?"
. First as stated in my comment reactivelist is deprecated.
There is a problem with the way the LoadUsers command is invoked.
One is you can do WhenActivated in your view model. You derive your view model from ISupportsActivation, your view will call the WhenActivated block inside your view when it's WhenActivated is called. See https://reactiveui.net/docs/handbook/when-activated/#viewmodels for ideas.
Second way is to use
this.WhenAnyValue(x => x.ViewModel.LoadUsers)
.Select(x => x.Execute())
.Switch()
.Subscribe()
.DisposeWith(disposables);
So the above says get the LoadUsers command, get the Execute() which is a observable, Switch() means only subscribe to the newest first, and dispose the old execute when a new value comes in, subscribe to that we will run the command, and dispose to stop potentially.
It looks like the issue wasn't scheduling, but async related.
IUserManagementService has a reference to an IUserRepository, which itself has an GetUsersAsync method to actually query the database. The actual implementation of IUserManagementService was missing ConfigureAwait on the call to IUserRepository.GetUsersAsync. This wasn't an issue in the unit tests, but definitely a problem once an UI was involved.
I like the Automatic HTTP 400 responses functionality new to ASP.NET Core 2.1 and it's working out really well for most cases.
However, in one action I need to do a bit of pre-processing before validation the payload. I have a custom validator that requires two values in the model to perform validation. One of those values is in the path so I would like to set that value on the model from the path then validate.
I don't want to switch the functionality off for all actions with:
public void ConfigureServices(IServiceCollection services)
{
services.Configure<ApiBehaviorOptions>(options =>
{
options.SuppressModelStateInvalidFilter = true;
});
}
Is there any way I could switch it off just for an individual action?
Edit:
I tried modifying the InvalidModelStateResponseFactory but it didn't solve my problem because I still need to get into the controller action:
services.Configure<ApiBehaviorOptions>(options =>
{
options.InvalidModelStateResponseFactory = actionContext =>
{
var ignore = actionContext.ActionDescriptor.FilterDescriptors.Any(fd => fd.Filter is SuppressModelStateInvalidFilterAttribute);
if (ignore)
{
// Can only return IActionResult so doesn't enter the controller action.
}
return new BadRequestObjectResult(actionContext.ModelState);
};
});
[AttributeUsage(AttributeTargets.Method)]
public class SuppressModelStateInvalidFilterAttribute : FormatFilterAttribute
{
}
Edit:
Here's a link to an issue I raised on the asp.net core repo in case I get anywhere with that - https://github.com/aspnet/Mvc/issues/8575
Update: you can just use the following code in ConfigureServices in Startup.cs:
services.Configure<ApiBehaviorOptions>(apiBehaviorOptions => {
apiBehaviorOptions.SuppressModelStateInvalidFilter = true;
});
Based on Simon Vane's answer, I had to modify the attribute for ASP.Net Core 2.2 as follows:
/// <summary>
/// Suppresses the default ApiController behaviour of automatically creating error 400 responses
/// </summary>
[AttributeUsage(AttributeTargets.Method)]
public class SuppressModelStateInvalidFilterAttribute : Attribute, IActionModelConvention {
private static readonly Type ModelStateInvalidFilterFactory = typeof(ModelStateInvalidFilter).Assembly.GetType("Microsoft.AspNetCore.Mvc.Infrastructure.ModelStateInvalidFilterFactory");
public void Apply(ActionModel action) {
for (var i = 0; i < action.Filters.Count; i++) {
if (action.Filters[i] is ModelStateInvalidFilter || action.Filters[i].GetType() == ModelStateInvalidFilterFactory) {
action.Filters.RemoveAt(i);
break;
}
}
}
}
I had a response from Microsoft - https://github.com/aspnet/Mvc/issues/8575
The following worked a charm.
[AttributeUsage(AttributeTargets.Method)]
public class SuppressModelStateInvalidFilterAttribute : Attribute, IActionModelConvention
{
public void Apply(ActionModel action)
{
for (var i = 0; i < action.Filters.Count; i++)
{
if (action.Filters[i] is ModelStateInvalidFilter)
{
action.Filters.RemoveAt(i);
break;
}
}
}
}
In my controller I could then make changes to the model before re-validating it (note the ModelState.Clear(), TryValidateModel add to existing model state):
if (model == null)
{
return BadRequest(ModelState);
}
model.Property = valueFromPath;
ModelState.Clear();
if (TryValidateModel(model) == false)
{
return BadRequest(ModelState);
}
You could play with ApiBehaviorOptions.InvalidModelStateResponseFactory property to handle specific cases based on actionContext details:
services.Configure<ApiBehaviorOptions>(options =>
{
options.InvalidModelStateResponseFactory = actionContext =>
{
// Do what you need here for specific cases with `actionContext`
// I believe you can cehck the action attributes
// if you'd like to make mark / handle specific cases by action attributes.
return new BadRequestObjectResult(context.ModelState);
}
});
This could probably be solved by implementing your own validator for your specific case. It is covered quite well in the documentation.
https://learn.microsoft.com/en-us/aspnet/core/mvc/models/validation?view=aspnetcore-2.1#custom-validation
Either that or possibly a custom model binder to create your model with all the preprocessing done before it is validated.
I encountered similar problem and came up with this solution.
public class SuppressModelStateInvalidFilterAttribute : ActionFilterAttribute
{
public SuppressModelStateInvalidFilterAttribute()
{
Order = -2500;
}
public override Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
context.ModelState.Clear();
return next.Invoke();
}
}
#RunWith(MockitoJUnitRunner.class)
public class MessageDataTest {
#InjectMocks
MessageData messageData;
#Test
public void testingMethod() throws Exception {
MessageData data = PowerMockito.spy(messageData); //passing the mocked object for spy
PowerMockito.when(data,"isMessageContains",anyString(),any()).thenReturn(true); // throwing exception here
MessageDataResponse response = messageFormatterData.constructData(messageItems);
assertNotNull(response);
}
}
MessageData.java
private boolean isMessageContains(String name, MessageResponse messageResponse) {
for (::) {
some logic
return true;
}
}
return false;
}
when I run the test case, I'm getting the below error,
org.mockito.exceptions.misusing.InvalidUseOfMatchersException: Misplaced argument matcher detected here
You cannot use argument matchers outside of verification or stubbing. Examples of correct usage of argument matchers: when(mock.get(anyInt())).thenReturn(null); doThrow(new RuntimeException()).when(mock).someVoidMethod(anyObject()); verify(mock).someMethod(contains("foo"))
Also, this error might show up because you use argument matchers with methods that cannot be mocked. Following methods cannot be stubbed/verified: final/private/equals()/hashCode(). Mocking methods declared on non-public parent classes is not supported
I want to mock this private "isMessageContains" to return always true.
Using AutoFixture with the AutoFixture.AutoMoq package, I sometimes find tests that weren't configured to correctly test the thing they meant to test, but the problem was never discovered because of the default (Loose) Mock behavior:
public interface IService
{
bool IsSomethingTrue(int id);
}
void Main()
{
var fixture = new Fixture()
.Customize(new AutoMoqCustomization());
var service = fixture.Freeze<Mock<IService>>();
Console.WriteLine(service.Object.IsSomethingTrue(1)); // false
}
I'd like to make Mocks get created with Strict behavior, so we're forced to call Setup() for the methods we expect to be called. I can do this for each individual mock like this:
fixture.Customize<Mock<IService>>(c => c.FromFactory(() => new Mock<IService>(MockBehavior.Strict)));
But after combing through source code for AutoMoqCustomization() and the various ISpecimenBuilder and other implementations, I'm pretty lost as to the best way to just make all Mocks get initialized with strict behavior. The framework appears to be very flexible and extensible, so I'm sure there's a simple way to do this--I just can't figure out how.
There's no simple built-in feature that will enable you to do something like that, but it shouldn't be that hard to do.
Essentially, you'd need to change MockConstructorQuery so that it invokes the constructor that takes a MockBehavior value, and pass in MockBehavior.Strict.
Now, you can't change that behaviour in MockConstructorQuery, but that class is only some 9-10 lines of code, so you should be able to create a new class that implements IMethodQuery by using MockConstructorQuery as a starting point.
Likewise, you'll also need to create a custom ICustomization that does almost exactly the same as AutoMoqCustomization, with the only exception that it uses your custom IMethodQuery with strict mock configuration instead of MockConstructorQuery. That's another 7 lines of code you'll need to write.
All that said, in my experience, using strict mocks is a bad idea. It'll make your tests brittle, and you'll waste a lot of time mending 'broken' tests. I can only recommend that you don't do this, but now I've warned you; it's your foot.
For those interested, down below you can find #MarkSeemann's reply translated into code. I am pretty sure it does not cover all use cases and it was not heavily tested. But it should be a good starting point.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Moq;
using Ploeh.AutoFixture;
using Ploeh.AutoFixture.AutoMoq;
using Ploeh.AutoFixture.Kernel;
namespace ConsoleApplication1
{
public class StrictAutoMoqCustomization : ICustomization
{
public StrictAutoMoqCustomization() : this(new MockRelay()) { }
public StrictAutoMoqCustomization(ISpecimenBuilder relay)
{
// TODO Null check params
Relay = relay;
}
public ISpecimenBuilder Relay { get; }
public void Customize(IFixture fixture)
{
// TODO Null check params
fixture.Customizations.Add(new MockPostprocessor(new MethodInvoker(new StrictMockConstructorQuery())));
fixture.ResidueCollectors.Add(Relay);
}
}
public class StrictMockConstructorMethod : IMethod
{
private readonly ConstructorInfo ctor;
private readonly ParameterInfo[] paramInfos;
public StrictMockConstructorMethod(ConstructorInfo ctor, ParameterInfo[] paramInfos)
{
// TODO Null check params
this.ctor = ctor;
this.paramInfos = paramInfos;
}
public IEnumerable<ParameterInfo> Parameters => paramInfos;
public object Invoke(IEnumerable<object> parameters) => ctor.Invoke(parameters?.ToArray() ?? new object[] { });
}
public class StrictMockConstructorQuery : IMethodQuery
{
public IEnumerable<IMethod> SelectMethods(Type type)
{
if (!IsMock(type))
{
return Enumerable.Empty<IMethod>();
}
if (!GetMockedType(type).IsInterface && !IsDelegate(type))
{
return Enumerable.Empty<IMethod>();
}
var ctor = type.GetConstructor(new[] { typeof(MockBehavior) });
return new IMethod[]
{
new StrictMockConstructorMethod(ctor, ctor.GetParameters())
};
}
private static bool IsMock(Type type)
{
return type != null && type.IsGenericType && typeof(Mock<>).IsAssignableFrom(type.GetGenericTypeDefinition()) && !GetMockedType(type).IsGenericParameter;
}
private static Type GetMockedType(Type type)
{
return type.GetGenericArguments().Single();
}
internal static bool IsDelegate(Type type)
{
return typeof(MulticastDelegate).IsAssignableFrom(type.BaseType);
}
}
}
Usage
var fixture = new Fixture().Customize(new StrictAutoMoqCustomization());
I'm trying to start using Unit Testing and I want to test the following Controller:
public class AjaxController : Controller
{
...
public JsonResult RateVideo( int userRating, long videoId )
{
string userName = User.Identity.Name;
...
}
}
I have a created a TestClass with the following method:
[ TestMethod
public void TestRateVideo()
{
//Arrange
AjaxController c = new AjaxController();
//Act
JsonResult jr = c.RateVideo(1, 1);
//Assert
//Not implemented yet
}
I select debug and run the test. When the code reaches the 1st statement:
string username = User.Identity.Name;
Debugging stops and I am presented with a message that says that the test failed.
Any guidance you can offer would be appreciated.
The most common problem testing Controllers is using functions that rely on the HttpContext.
The implementation of the User property is something like:
public IPrincipal get_User()
{
if (this.HttpContext != null)
{
return this.HttpContext.User;
}
return null;
}
As you can see, User will return null because the HtppContext has not being initialized and calling .Identity will throw an exception.
Fortunately MVC lets you set the ControllerContext property so you can create your own instance with a mocked HttpContext.
The MVCContrib project has some test helpers. You can use the TestControllerBuilder in MVCContrib.TestHelper.dll to build your controllers inside your test classes with mocked context.