Hey,
I'm working with mvc I have to write unit test for function that contains
var result = ViewEngines.Engines.FindPartialView(context, partialPath);
and my test fails on this part : "The RouteData must contain an item named 'controller' with a non-empty string value."How can I make face object for this?
thx
add that for controller
var routeData = new RouteData();
routeData.Values.Add("controller", "someName");
routeData.Values.Add("action", "someAction");
Related
Trying to unit test the navigation in one of my command calls into a private method. Just trying to test if the navigation request has been made as a result of this command execution.
There's the old documentation;
https://www.mvvmcross.com/documentation/fundamentals/testing
This documentation does not factor in new async based calls as far as I found; For example IMvxMainThreadAsyncDispatcher
Either we need to implement two ExecuteOnMainThreadAsync methods or inherit from MvxMainThreadAsyncDispatcher in MockDispatcher.
Also need to add IMvxMainThreadAsyncDispatcher in IoC registration.
var mockDispatcher = new MockDispatcher();
...
...
Ioc.RegisterSingleton<IMvxMainThreadAsyncDispatcher>(MockDispatcher);
So almost all tests work except navigation call requests. Below method inside MockDispatcher never gets called so I can't check request counts;
public async Task<bool> ShowViewModel(MvxViewModelRequest request)
{
Requests.Add(request);
return true;
}
Anybody has a working code that would mock and gets this Request called or in some other form? IMvxMainThreadDispatcher is being set as absolute, and navigation calls are not done with ShowViewModel<>() anymore in MVVMCross, it's done by calling navigationService.Navigate();
Well, I have found the solution to my question... The ShowViewModel is called when navigation service is properly mocked. I have found a piece of code on GitHub from MvvmCross's own repo on how they do tests for navigation. My next challenge would be to mock the destination viewModel but that's separate and below code doesn't cover that. Previously I had a very basic IMvxNavigationService mock.
var mockLocator = new Mock<IMvxViewModelLocator>();
mockLocator.Setup(
m => m.Load(It.IsAny<Type>(), It.IsAny<IMvxBundle>(), It.IsAny<IMvxBundle>(), It.IsAny<IMvxNavigateEventArgs>())).Returns(() => new FakeViewModel());
mockLocator.Setup(
m => m.Reload(It.IsAny<IMvxViewModel>(), It.IsAny<IMvxBundle>(), It.IsAny<IMvxBundle>(), It.IsAny<IMvxNavigateEventArgs>())).Returns(() => new FakeViewModel());
var mockCollection = new Mock<IMvxViewModelLocatorCollection>();
mockCollection.Setup(m => m.FindViewModelLocator(It.IsAny<MvxViewModelRequest>()))
.Returns(() => mockLocator.Object);
Ioc.RegisterSingleton(mockLocator.Object);
var loader = new MvxViewModelLoader(mockCollection.Object);
_navigationService = new MvxNavigationService(null, loader)
{
ViewDispatcher = MockDispatcher,
};
_navigationService.LoadRoutes(new[] { typeof(YourViewModelTestClass).Assembly });
Ioc.RegisterSingleton<IMvxNavigationService>(_navigationService);
As pointed out in this anwer to Asp.Net Core 2.1 ApiController does not automatically validate model under unit test, the automatic ModelState validation that ASP.NET Core 2.1's ApiControllerAttribute gives us only works when actualyy requestion the action at runtime, not by calling it with an invalid parameter in a unit test.
However, I still want to test if my action actually returns a BadRequestResult when supplying an incorrect model. Is there any way of doing this? I get that I can still manually check if ModelState.IsValid is false, and returning BadRequest() myself, but that kind of defeats the point of the automatic validation.
Am I stuck manually checking ModelState.IsValid after all, or is there a way to make use of the new ApiControllerAttribute model validation in a unit test?
If you want to validate that the api's are returning a badrequest when the data annotations are broken then you need to do an api integration test.
One nice option is to run the integration tests via an in-memory client using the TestServer
Here's an example:
//arrange
var b = new WebHostBuilder()
.UseStartup<YourMainApplication.Startup>()
.UseEnvironment("development");
var server = new TestServer(b) { BaseAddress = new Uri(url) };
var client = server.CreateClient();
var json = JsonConvert.SerializeObject(yourInvalidModel);
var content = new StringContent(json, Encoding.UTF8, "application/json");
//act
var result = await client.PostAsync("api/yourController", content);
//assert
Assert.AreEqual(400, (int)result.StatusCode);
If you only need to make sure that the annotations is proper setup you can manually trigger the validation via the TryValidateObject method
var obj = new YourClass();
var context = new ValidationContext(obj);
var results = new List<ValidationResult>();
var valid = Validator.TryValidateObject(obj, context, results, true);
I'm trying to test some application logic that is dependent on the Values property in ControllerContext.RouteData.
So far I have
// Arrange
var httpContextMock = new Mock<HttpContextBase>(MockBehavior.Loose);
var controllerMock = new Mock<ControllerBase>(MockBehavior.Loose);
var routeDataMock = new Mock<RouteData>();
var wantedRouteValues = new Dictionary<string, string>();
wantedRouteValues.Add("key1", "value1");
var routeValues = new RouteValueDictionary(wantedRouteValues);
routeDataMock.SetupGet(r => r.Values).Returns(routeValues); <=== Fails here
var controllerContext = new ControllerContext(httpContextMock.Object, routeDataMock.Object, controllerMock.Object);
The unit test fails with:
System.ArgumentException: Invalid setup on a non-overridable member:
r => r.Values
Creating a fake RouteData doesn't work either as the constructor is RouteData(RouteBase,IRouteHandler).
The important class here is the abstract class RouteBase which has the method GetRouteData(HttpContextBase) which returns an instance of RouteData, the class I'm trying to fake. Taking me around in circles!
Any help on this would be most welcome.
RouteData also has a constructor that takes no arguments. Simply create one and add the values to it that you want. No need to mock it when you can create one.
var routeData = new RouteData();
routeData.Values.Add( "key1", "value1" );
var controllerContext = new ControllerContext(httpContextMock.Object, routeData, controllerMock.Object);
I'm very new to TDD in conjunction with mock objects, but a lesson I learned early on from a colleague was not to mock types you don't own. Thus, don't try to mock RouteData. The idea was originally conceived by Joe Walnes (though I can't find where he said it).
Edit: Why doesn't Moq run the overridden ToString method? gives the hint. I had to set filtermock.CallBase to true. Now it works.
I'm trying to write a unittest for an asp.net webapi project. What I want to do is, to test a function with its corresponding filter. I setup the controller and the filter moq objects like this:
var filtermock= new Mock<MyActionFilterAttribute>();
filtermock.SetupGet(attr => attr.UserId).Returns(userName);
[...]
var controllermock = new Mock<MyController>();
var filtermock = new Mock<MyActionFilterAttribute>();
The unittest looks like this:
var controller = controllermock.Object;
var filter = filtermock.Object;
await filter.OnActionExecutingAsync(null, CancellationToken.None);
await controller.MyTestFunction();
await filter.OnActionExecutedAsync(null, CancellationToken.None);
The problem is, that the overridden functions OnActionExecutingAsync and OnActionExecudedAsync are not beeing called when i run/debug the test. I guess the baseclasses of ActionFilterAttribute are called? Could anyone give me a hint what I am doing wrong here?
How do you expect filtermock to ever be called? It does not appear the filtermock is associated to the controllermock so the controllermock is not even aware of the filtermock.
This is the same issue I am trying to resolve myself: how to inject an action filter into a controller.
I'm working on building up Unit Tests for our SignalR 2.x implementation.
Our implementation utilizes accessing request cookies stored in the Context.
So, to build out our unit tests, we have to create a mocked cookie collection
and associate it with the mocked request object.
I've seen the following code block that does this in SignalR 1.x:
const string connectionId = "1234";
const string hubName = "Chat";
var mockConnection = new Mock<IConnection>();
var mockUser = new Mock<IPrincipal>();
var mockCookies = new Mock<IRequestCookieCollection>();
var mockPipelineInvoker = new Mock<IHubPipelineInvoker>();
var mockRequest = new Mock<IRequest>();
mockRequest.Setup(r => r.User).Returns(mockUser.Object);
mockRequest.Setup(r => r.Cookies).Returns(mockCookies.Object);
StateChangeTracker tracker = new StateChangeTracker();
Clients = new HubConnectionContext(mockPipelineInvoker.Object, mockConnection.Object, hubName, connectionId, tracker);
Context = new HubCallerContext(mockRequest.Object, connectionId);
I'm running into issues trying to create the mocked cookie collection.
IRequestCookieCollection above is undefined.
var mockCookies = new Mock<IRequestCookieCollection>();
Did this move somewhere else in the SignalR libraries?
Or.., is there a different way to do this??
Thanks,
JohnB
In SignalR 1.0, the type of IRequest.Cookies was changed from IRequestCookieCollection to IDictionary<string, Cookie>. As part of this change, IRequestCookieCollection was removed.
Changing mockCookies to reflect to the new type should fix your issue:
var mockCookies = new Mock<IDictionary<string, Cookie>>();
However, it might be painful mocking out an IDictionary, so it is probably easier to use a normal Dictionary instead:
var cookies = new Dictionary<string, Cookie>();
// ...
mockRequest.Setup(r => r.Cookies).Returns(cookies);
https://github.com/SignalR/SignalR/issues/1034