Mock Unit tests for Linq statements in .Net core 2.2 always return null - unit-testing

I know lots of mocking questions are asked, but none worked with me.
I'm trying to write a unit test for a service I have. The service have the following line of code
var assignments = await _assignmentRepository.WhereAsync(as => as.DepartmentId == departmentId);
Here's the implementation of WhereAsync method:
public async Task<List<T>> WhereAsync(Expression<Func<T, bool>> expression)
{
return await _dbContext.Set<T>().Where(expression).ToListAsync();
}
Here's my mock test statement (listAssignments is a predefined variable):
_assignmentRepository.Setup(rep => rep.WhereAsync(as => It.IsAny<bool>())).ReturnsAsync(listAssignments);
I know that we can't Mock Where and FirstOrDefault methods, but isn't there a way to mock my web service WhereAsync method??

As Tseng mentioned in the comment above. We don't mock the DbContext, we mock the repository itself.
So I used the InMemoryDatabase testing. Added some data to my in-memory database which made my DbContext return the data I want.
var mapOptions = new DbContextOptionsBuilder<MapViewerContext>()
.UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString())
.Options;
var identityOptions = new DbContextOptionsBuilder<AppIdentityDbContext>()
.UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString())
.Options;
var mapContext = new MapViewerContext(_configuration.Object, mapOptions);
var appIdentityContext = new AppIdentityDbContext(_configuration.Object, identityOptions);

Related

Unit test controller using UrlHelper with NSubstitute

I'm using MVC5 and NSubstitute. I'm trying to create unit test to verify the model is being properly created for some controller actions.
The problem I have is that the controller is using a model within which I have something along the lines of:
Url = new UrlHelper(Request.RequestContext).Action("Browse")
Any time I try to test this controller method, I get a null object exception. I have tried a lot of different ways to try and mock the context, but it never seems to quite work. Can anyone help?
I've referred to many SO question including;
ASP.NET MVC: Unit testing controllers that use UrlHelper
Which isn't so helpful to me as I'm using NSubstitute.
I was trying to use a MockHttpContext helper method I had found:
public static T MockHttpContext<T>(this T controller) where T : Controller
{
controller.ControllerContext = new ControllerContext
{
HttpContext = GetHttpContextMock()
};
controller.Url = new UrlHelper(controller.ControllerContext.RequestContext);
return controller;
}
private static HttpContextBase GetHttpContextMock()
{
var routes = new RouteCollection();
var actionExecutingContext = Substitute.For<ActionExecutingContext>();
var httpContextBase = Substitute.For<HttpContextBase>();
var httpServerUtilityBase = Substitute.For<HttpServerUtilityBase>();
var httpResponseBase = Substitute.For<HttpResponseBase>();
var httpRequestBase = Substitute.For<HttpRequestBase>();
var httpSessionStateBase = Substitute.For<HttpSessionStateBase>();
actionExecutingContext.HttpContext.Returns(httpContextBase);
httpContextBase.Request.ApplicationPath.Returns("");
httpContextBase.Response.ApplyAppPathModifier(Arg.Any<string>())
.Returns(ctx => ctx.Arg<string>());
httpContextBase.Request.Returns(httpRequestBase);
httpContextBase.Response.Returns(httpResponseBase);
httpContextBase.Server.Returns(httpServerUtilityBase);
httpContextBase.Session.Returns(httpSessionStateBase);
httpRequestBase.Cookies.Returns(new HttpCookieCollection());
return httpContextBase;
}
I was trying to do the same thing. This worked for me:
controller.Url = Substitute.For<UrlHelper>();
controller.Url.Action(Arg.Any<string>(), Arg.Any<string>()).Returns("something");
Then when I call my controller action, it does not crash when dereferencing the UrlHelper. Of course you have to mock up (NSubstitute) the controller properly. I hope this works. I can post more code for mocking the controller if you need.

How to mock UmbracoContext for unit testing?

I am writing unit tests for ASP.NET MVC application using RhinoMocks and Umbraco. For this I need to mock UmbracoContext, and so used below code.
But Umbraco.Core.ApplicationContext.Current throws ArgumentNullException. Please suggest resolution for this:
var contextBase = MockRepository.GenerateMock<HttpContextBase>();
var request = MockRepository.GenerateMock<HttpRequestBase>();
var response = MockRepository.GenerateMock<HttpResponseBase>();
var session = MockRepository.GenerateMock<HttpSessionStateBase>();
var server = MockRepository.GenerateMock<HttpServerUtilityBase>();
contextBase.Stub(ctx => ctx.Request).Return(request);
contextBase.Stub(ctx => ctx.Response).Return(response);
contextBase.Stub(ctx => ctx.Session).Return(session);
contextBase.Stub(ctx => ctx.Server).Return(server);
var umbracoCtx = UmbracoContext.EnsureContext(contextBase, Umbraco.Core.ApplicationContext.Current);

AngularJS - Unit testing file uploads

As you know, inside unit tests it's built-in angularjs feature to mock XHR requests with $httpBackend - this is nice and helpful while writing unit tests.
Recently, I met with need of mocking XHR in case of file upload and discovered some problems.
Consider following code:
var xhr = new XMLHttpRequest();
xhr.upload.addEventListener("progress", uploadProgress(event), false);
xhr.addEventListener("load", uploadComplete(event), false);
xhr.addEventListener("error", uploadError(event), false);
xhr.addEventListener("abort", uploadAbort(event), false);
xhr.open("POST", 'some url');
xhr.send(someData);
What I want to do is to do unit testing of such a code with mocking of XHR requests, but it's not possible do it because there is no $http service used here.
I tried this (and it's working and could be mocked with $httpBackend):
$http({
method: 'POST',
url: 'some url',
data: someData,
headers: {'Content-Type': undefined},
transformRequest: angular.identity})
.then(successCallback, errorCallback);
But in this case I don't know how to implement 'progress' callback and 'abort' callback (they are essential and required in case I am working on now).
I've seen information that latest Angular supports progress callback for promises (not sure though whether it's integrated with $http service), but what about abort callback?
Any ideas or maybe your met with something similar before?
If the $http service doesn't give you everything you need, you can still unit test the first block of code. First of all, change your code to use Angular's $window service. This is just a wrapper service, but it allows you to mock the object in your tests. So, you'll want to do this:
var xhr = new $window.XMLHttpRequest();
Then in your tests, just mock it and use spies.
$window.XMLHttpRequest= angular.noop;
addEventListenerSpy = jasmine.createSpy("addEventListener");
openSpy = jasmine.createSpy("open");
sendSpy = jasmine.createSpy("send");
xhrObj = {
upload:
{
addEventListener: addEventListenerSpy
},
addEventListener: addEventListenerSpy,
open: openSpy,
send: sendSpy
};
spyOn($window, "XMLHttpRequest").andReturn(xhrObj);
From there, you can make the different spies return whatever you want for the different tests.
You should mock $http and control any deferred, as you want more control over your test. Basically, mock $http provider and serve a custom implementation that exposes its deferred, then play with it.
You should not worry whether $http is working right or not, because it is supposed to, and is already tested. So you have to mock it and only worry testing your part of the code.
You should go something like this:
describe('Testing a Hello World controller', function() {
beforeEach(module(function($provide) {
$provide.provider('$http', function() {
this.$get = function($q) {
return function() {
var deferred = $q.defer(),
promise = deferred.promise;
promise.$$deferred = deferred;
return promise;
}
};
});
}));
it('should answer to fail callback', inject(function(yourService, $rootScope) {
var spyOk = jasmine.createSpy('okListener'),
spyAbort = jasmine.createSpy('abortListener'),
spyProgress = jasmine.createSpy('progressListener');
var promise = yourService.upload('a-file');
promise.then(spyOk, spyAbort, spyProgress);
promise.$$deferred.reject('something went wrong');
$rootScope.$apply();
expect(spyAbort).toHaveBeenCalledWith('something went wrong');
}));
});
And your service is simply:
app.service('yourService', function($http) {
return {
upload: function(file) {
// do something and
return $http({...});
}
};
});
Just note that promises notification is only available in the latest RC release. So, if you can't use it, just elaborate a little more the example and mock the XHR events and so.
Also note that you should preferably have one test case for each of the callbacks (fail, success and progress), in order to follow KISS principle.

Testing AngularJS controllers with resource services

Background:
I'm writing unit test for angular js controllers, which utilize angular $resources wrapped in services (for maintainability purposes).
Example controller:
name = 'app.controllers.UsersIndexCtrl'
angular.module(name, [])
.controller(name, [
'$scope'
'$location'
'$dialog'
'Users'
'UserRoles'
($scope, $location, $dialog, Users, UserRoles) ->
# Get users list
$scope.users = Users.query()
# rest...
])
Example resource service:
angular.module('app.services.Users', [])
.factory 'Users', ['$rootScope', '$http', '$resource', '$location' , ($rootScope, $http, $resource, $location)->
baseUrl = '/users'
Users = $resource baseUrl + '/:userId', {userId: '#_id'}
Users.getStatus = ->
console.log 'User::getStatus()'
req = $http.get baseUrl + '/status'
req.success (res)->
$rootScope.globalUserAccountSettings = res
unless $rootScope.$$phase then $rootScope.$apply()
# other, custom methods go here...
])
Most of unit test examples in angular suggest using $httpBackend and thus mocking the $http service in controllers. To be honest, I doubt if it's a good practice since if did so I'd have to hardcode request paths in all controller tests and I want to isolate unit behaviour. $httpBackend mock is really great but only if you are using $resource in controllers directly.
A typical single test using $httpBackend would look like:
it 'should be able to add a new empty user profile', ->
$httpBackend.flush()
l = $scope.users.length
$httpBackend.expect('POST', '/users').respond _.cloneDeep mockResponseOK[0]
$scope.add()
$httpBackend.flush()
expect($scope.users.length).toEqual l + 1
What if I created a mock User resource class instance, something like:
angular.module('app.services.Users', [])
.factory 'Users', ->
class Users
$save:(cb)->
$remove:->
#query:->
#get:->
Angular DI mechanisms will override old 'app.services.Users' module with this one in a transparent way and enable me to run checks with jasmine spies.
What bothers me is the fact that I wasn't able to find a single example supporting my idea. So the question is, which one would you use and why or what am I doing wrong?
I think it makes much more sense to stub this at a service level with Jasmine spies, as you suggested. You're unit testing the controller at this point, not the service -- the exact way in which an http request is made should not be a concern for this test.
You can do something in your spec like this:
var Users = jasmine.createSpyObj('UsersStub', ['query', 'get']);
beforeEach(inject(function($provide) {
$provide.factory('Users', function(){
return Users;
});
});
And then in your relevant tests, you can stub the individual service methods to return what you expect using methods like "andCallFake" on your spy object.
The best thing you can do is make a fake resource with the methods that were suppose to be called:
var queryResponse = ['mary', 'joseph'],
Users = function() {
this.query = function() {
return queryResponse;
},
scope, HomeCtrl;
};
beforeEach(inject(function($rootScope, $controller) {
scope = $rootScope.$new();
HomeCtrl = $controller('HomeCtrl', {$scope: scope, Users: new Users()});
}));
it('has users in scope', function() {
expect(scope.users).toEqual(queryResponse);
});
I'm a newbie at this stuff. I've been writing my tests using coffeescript using a dsl, but I've ran into a similar problem today. The way I solved it was by creating a jasmine spy for my resource. Then I created a promise. When the promise is resolved, it will call the 'success' function that you pass in in the controller. Then in the 'it' method, I actually resolve the promise.
I think the code would look something like this using js and jasmine, but I didn't actually have time to check
beforeEach(inject(function($rootScope, $controller, $q ) {
scope = $rootScope.$new();
queryPromise = $q.defer()
User = jasmine.createSpyObject("UsersStub", ["query"]);
User.query.andCallFake(function(success,errror){queryPromise.promise.then(success,error)});
HomeCtrl = $controller('HomeCtrl', {$scope: scope, Users: new Users()});
}));
it('has users in scope', function() {
queryPrmomise.resolve({User1: {name"joe"})
expect(scope.users).toEqual(queryResponse);
});

Is there a way to unit test ASP.NET MVC ViewBag properties set in the view?

Say I have a view with the following code at the top of the page:
#{
ViewBag.Title = "About Us";
Layout = "~/Views/Shared/_Layout.cshtml";
}
And I have a controller method:
public ActionResult About()
{
return View();
}
How can I test that the ViewBag was set properly?
I have tried the following code.
[TestCase]
public void About()
{
var controller = new AboutController();
var ar = controller.About() as ViewResult;
Assert.AreEqual("About Us", ar.ViewBag.Title);
}
But I get the following result when I run the test:
Tests.Controllers.AboutControllerTests.About():
Expected: "About Us"
But was: null
Since both the ViewData and ViewBag use the same storage pattern, you should be able to use ViewData[yourKey] in your tests.
So your test will look like this:
[TestCase]
public void About()
{
var controller = new AboutController();
var ar = controller.About() as ViewResult;
Assert.AreEqual("About Us", ar.ViewData["Title"]);
}
Have you tried
Assert.AreEqual("About Us", controller.ViewBag.Title);
It works for me
The ViewResult returned by a controller has only a reference to the view that should be shown. The view is not even resolved at this time. The code there is never executed by your test.
What you should do is set ViewBag properties in the controller, not the view. Usually, the view will only read such values.
hope it helps
No, you cannot test views like this. The closest you might get is to render the view into a stream writer and then test the generated HTML. It is not something that is commonly done in unit tests. I would recommend you performing web tests in order to verify that the views are correct. You could create web tests with Visual Studio or there's also the free Selenium framework.
For what its worth, I found that the following worked fine:
Assert.AreEqual(_layout, result.ViewBag.Layout);
With result being the ViewResult
[TestMethod]
public async Task GetData() {
CtrlNameController controller = new CtrlNameController();
controller.ViewData["UserId"] = 1;
ViewResult result = await controller.GetData() as ViewResult;
Assert.IsNotNull(result);
}
ViewData["UserId"] is equal to View.UserId