Dependency Variable Doesnt Exist - unit-testing

Newbie in coldbox so please have patience with me.
I am trying to implement TDD on my coldbox application.
Under my service model I inject this dependency.
property name="wirebox" inject="wirebox"
property name="populator" inject="wirebox:populator";
On my service model I have this method. GetallUsers()
User function new(){
return wirebox.getInstance("User");
}
function getAllUsers(){
var users= queryExecute(
"SELECT * FROM USERS",
{},
{returnType="array"}
).map(function(user){
return populator.populateFromStruct(new(),user);
});
return users;
}
And on my UserServiceTest I have this code:
component extends="coldbox.system.testing.BaseModelTest" model="models.UserService"{
/*********************************** LIFE CYCLE Methods ***********************************/
function beforeAll(){
super.beforeAll();
// setup the model
super.setup();
// init the model object
model.init();
}
function afterAll(){
super.afterAll();
}
/*********************************** BDD SUITES ***********************************/
function run(){
describe( "Users Suite", function(){
it( "can get list of users", function(){
var stubPopulator = stub().$( 'populateFromStruct', {} );
model.$property( 'populator', 'variables', stubPopulator );
var users= model.getAll();
expect( event.getPrivateValue( "users") ).toBeStruct();
});
});
}
But I got this error saying **variable [POPULATOR] doesn't exist**.
Hoping someone can help me.

You didn't show the full test bundle, but based on the name it would appear it is a unit test (or a ColdBox model test, which is a type of unit test). Unit tests do not spin up the ColdBox framework by default and do not process injections for the CFCs under test. They are created "naked" and it's up to you to provide mocks for an dependencies that CFC has.
So in this case, you'd need to provide a mock populator to your model to be used for the test. So something like this:
var stubPopulator = createStub().$( 'populateFromStruct', {} )
model.$property( 'populator', 'variables', stubPopulator )
var users= model.getAll();
My stubed populator just returns an empty struct. It's also worth noting I don't think your queryMap() is returning a struct like you think it is so you may need to confirm the functionality of that method.
Alternatively, you could switch to more of an integration test where you set this.loadColdBox to true in your test CFC's pseduo-constructor and then use getInstance( 'UserService' ) to get a fully built instance of your UserService which would have the populator injected into it. Exactly how this would look like depends on several things you haven't shared such as your test harness setup, and your test bundle CFC's base class.

Related

Sinon Mock of Mongoose Save method for all future instances of a Model (with promises)

I am trying to accomplish mocking the Mongoose save method for all instances of a particular Model during a unit test case (Sinon,Mocha, Chai) using promises. I am using sinon-mongoose and sinon-as-promised per several other examples. I am trying to get to something like this end state of test code:
var expect = require('chai').expect;
var sinon = require('sinon');
require('sinon-as-promised');
require('sinon-mongoose');
/* Mongoose schema+model for User method persist */
var UserModel = require('./models').userModel;
/* code module that will be tested */
var userMethods = require('./user');
/* unit test setup*/
var userModelMock = sinon.mock(UserModel);
/* mock all instances of UserModel saves with a forced error return to test code modules */
userModelMock.expects('save')
.chain('exec')
.rejects('error saving');
/* call code module method for testing that creates new instance of UserModel and receives mocked save error*/
return userMethods.addUser().then(function(result){
expect(result).to.equal(false);
userModelMock.restore();
});
I realize the save method is a per instance method so the above mock doesn't work "globally" or within the called addUser() method under test (addUser() doesn't see the mock and hits the database).
Is there some way to reference the Schema Object or other object property to mock all subsequent instances with out creating custom object wrappers or using other esoteric methods? The last answer on this SO post (not the marked answer) comes closest but it only works for a specific instance of a model: Stubbing a Mongoose model using Sinon
I was able to develop a solution based on the suggestion of #Merott (Github) as described in the following issue discussion for sinon-mongoose (although there is some discussion about manipulating the prototype): https://github.com/underscopeio/sinon-mongoose/issues/7
Essentially I had to add the following code ahead of my save mocks and work off the model prototype:
Object.defineProperty(UserModel.prototype, 'save', {
value: UserModel.prototype.save,
configurable: true,
});
The full code snippet above with the appropriate adjustments:
var expect = require('chai').expect;
var sinon = require('sinon');
require('sinon-as-promised');
require('sinon-mongoose');
/* Mongoose schema+model for User method persist */
var UserModel = require('./models').userModel;
/* code module that will be tested */
var userMethods = require('./user');
/* unit test setup*/
Object.defineProperty(UserModel.prototype, 'save', {
value: UserModel.prototype.save,
configurable: true,
});
var userModelMock = sinon.mock(UserModel.prototype);
/* mock all instances of UserModel saves with a forced error return to test code modules */
userModelMock.expects('save')
.chain('exec')
.rejects('error saving');
/* call code module method for testing that creates new instance of UserModel and receives mocked save error*/
return userMethods.addUser().then(function(result){
expect(result).to.equal(false);
userModelMock.restore();
});
The only issue I saw was post Mock.restore(). If I wanted to return to normal database calls via save(), I saw some issues post mock restore(). Since I am mocking all my database calls it wasn't relevant, but it could be an issue for those needing a mix of mocks and real calls.

Moq out parameters

I'm fairly new to using Moq and Nunit for unit testing and I'm having issues with one scenario. What I want is for my mock to have an out parameters which my system under test will then use to decide what action to take.
My system under test is an MVC API controller and in particular I'm trying to test the POST method. I want to return an error message for the object when validation fails.
Here is the method code for the controller:
public IHttpActionResult Post(Candidate candidate)
{
try
{
if(candidate==null)
return BadRequest();
IEnumerable<string> errors;
_candidateManager.InsertCandidate(candidate, out errors);
if (errors!=null && errors.Any())
return BadRequest(CreateErrorMessage("Invalid candidate: ", errors));
return CreatedAtRoute("DefaultApi", new {id = candidate.CandidateId}, candidate);
}
catch (Exception)
{
return InternalServerError();
}
}
This is my Unit Test Code:
[Test]
[Category("CandidateManagerController Unit Tests")]
public void Should_Return_Bad_Request_When_Creating_Invalid_Candidate()
{
IEnumerable<string> errors = new List<string>() {"error1", "error2"};
var mockManager = new Mock<ICandidateManager>();
mockManager.Setup(x => x.InsertCandidate(new Candidate(), out errors)).Callback(()=>GetErrors(errors));
var sut = new CandidateManagerController(mockManager.Object);
var actionResult = sut.Post(new Candidate());
Assert.IsInstanceOf<BadRequestResult>(actionResult);
}
What I expect is that when _candidateManager.InsertCandidate() is run then the errors variable is populated. However what is happening is that when you step through the controller code errors is null after _candidateManager.InsertCandidate() method is run.
If anyone has any ideas what I'm doing wrong or if what I want to do is not possible using Moq then please let me know.
Thanks
What you want to do is possible. If you look at the Quickstart docs at https://github.com/Moq/moq4/wiki/Quickstart, there is a section where it shows how you do setups for methods using out params. I have made two corrections to your code and it works.
You have to use the same candidate instance for both the mock setup and when you exercise the sut. Otherwise, Moq thinks that the two objects are different and your test setup becomes useless.
You don't have to use Callback in order to set the errors returned by the mocked CandidateManager.
Below is your test method with my changes.
[Test]
[Category("CandidateManagerController Unit Tests")]
public void Should_Return_Bad_Request_When_Creating_Invalid_Candidate()
{
IEnumerable<string> errors = new List<string>() {"error1", "error2"};
//instance to be used for both setup and test later
var candidate = new Candidate();
var mockManager = new Mock<ICandidateManager>();
//removed Callback
mockManager.Setup(x => x.InsertCandidate(candidate, out errors));
var sut = new CandidateManagerController(mockManager.Object);
var actionResult = sut.Post(candidate);
Assert.IsInstanceOf<BadRequestResult>(actionResult);
}
You have to make sure that when you call your SUT that you use the same instance passed to the out argument otherwise the call will fail.
In your example, the method under test passes a null instance into the mocked method thus negating the setup of the test.
If however you are not able to supply the same instances for the out then it doesn't look like you will be able to get a mock to pass successfully. Take a look a the Quick Start for Moq to get an understanding of it capabilities.

webapi: unittest ActionFilterAttribute OnActionExecutingAsync with moq

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.

Unittesting and mocking robotlegs service calls using Oil extension

I have an ExampleModel that calls to an ExampleService that retrieves data from our backend. I can't figure out how to write unit tests for my application; which is structured as shown below:
ExampleService
public function retrieveMyToDoList(parameters):Promise
{
var promise:Promise = performRequest({request: "call to backend", parameters: values, session_id: clientModel.sessionID});
promise.addResultProcessor(parseRetrieveToDoListResult);
return promise;
}
protected function parseRetrieveToDoListResult(data:Object, callback:Function):void
{
does some JSON parsing into an object
callback(null, object containing my retrieved data)
}
ExampleModel
public function getMyToDoList():Promise
{
var promise:Promise = exampleService.retrieveToDoList(parameters);
promise.addResultHandler(onGetToDoListResult);
promise.addErrorHandler(onGetToDoListError);
return promise;
}
private function onGetHeadrsByUserResult(promise:Promise):void
{
// where this event will be listened to by mediators etc
dispatchEvent(new ResponseEvent(GOOD_RESULT));
}
private function onGetHeadrsByUserError(promise:Promise):void
{
dispatchEvent(new ResponseEvent(BAD_RESULT));
}
I'm trying to use asmock to mock my Service so that I can test my Model and how it handles the various results in the resulting Object but how do I mock the callback? I saw examples where the return values were mocked but in my case I'm using the Promise and callback and I'm not too sure how to go ahead.
If someone could please advise.
Thanks!
You can let the mock service return a real promise and call the handleResult method of the promise directly.
FYI: it's not a good idea to have a direct dependency from the model to the service. You should let the service manipulate the model, or pass the results from the service to a command which will manipulate the model. Models should never depend on anything else than helper classes.

Grails: How do you unit test a command object with a service injected into it

I am trying to test a Controller
that has a Command object with data binding.
The Command Object has a Service injected into it.
But When I try test the command object the injected service method
is never found as it is never "injected"
Is there a way to mock a service inside a command object?
Test method
void testLoginPasswordInvalid() {
mockRequest.method = 'POST'
mockDomain(User, [new User(login:"freddy", password:"realpassword")])
mockLogging(UserService) // userService mocked
MockUtils.prepareForConstraintsTests(LoginCommand)
def userService = new UserService()
def user = userService.getUser("freddy")//Gets called and returns the mockDomain
assert userService.getUser("freddy")//Passes
def cmd = new LoginCommand(login:"freddy", password:"letmein")
cmd.validate() // Fails (userService is nevr injected)
controller.login(cmd)
assertTrue cmd.hasErrors()
assertEquals "user.password.invalid", cmd.errors.password
assertEquals "/store/index", renderArgs.view
}
The getUser() method of the userService isn't found
Cannot invoke method getUser() on null object
java.lang.NullPointerException: Cannot invoke method getUser() on null object
Code
The login method of the controller being called,
def login = { LoginCommand cmd ->
if(request.method == 'POST') {
if(!cmd.hasErrors()){
session.user = cmd.getUser()
redirect(controller:'store')
}
else{
render(view:'/store/index', model:[loginCmd:cmd])
}
}else{
render(view:'/store/index')
}
}
The Command Object has a "userService" injected into it.
The validator calls this userService to find a user
class LoginCommand {
def userService
String login
String password
static constraints = {
login blank:false, validator:{ val, cmd ->
if(!cmd.userService.getUser()){
return "user.not.found"
}
}
}
The userService.getUser() looks like this.
class UserService {
boolean transactional = true
User getUser(String login) {
return User.findByLogin(login)
}
}
Service injection is done using Spring autowire-by-name. (Grep the Grails source tree for autowire to find a nice code fragment you can use to get it to autowire your controllers for you in integration tests.) This only functions in integration tests, where there's a Spring application context around that has the beans that can be injected.
In unit tests, you have to do this yourself since there's no Spring-land surrounding your stuff. This can be a pain, but gives you some benefits:
1) It's easy to inject mock versions of services - for example, using an Expando - in order to more closely specify the behavior of your controller's collaborating services, and to allow you to test only the controller logic rather than the controller and service together. (You can certainly do the latter in a unit test as well, but you have the choice of how to wire it up.)
2) It forces you to be explicit about the dependencies of your controller - if you depend on it, your tests will show it. This makes them a better specification for the behavior of your controller.
3) You can mock only the pieces of external collaborators your controller depends on. This helps your tests be less fragile - less likely to need to change when things change.
Short answer: your test method needs a cmd.userService = userService line.
What John says is on the mark. One example might be:
def mockUsers = [new User(login:"freddy", password:"realpassword")]
mockDomain(User, mockUsers)
def userService = [getUser:{String login -> mockUsers[0]}] as UserService
def cmd = new LoginCommand (/*arguments*/)
cmd.userService = userService
You can lookup other ways to mock objects at http://groovy.codehaus.org/Groovy+Mocks