How to initialize 'BehaviorSubject' in test Component? - unit-testing

In TS File,Datasource is initialised in a following way,
public dataSource: Observable = new BehaviorSubject([]);
How to Initialize in SPEC file

In the .spec file, you will need to seed your datasource with an initial state, as per test practices. In javascript:
const datasource = new BehaviorSubject("a");
Additional: then run function to test that acts on datasource, i.e.:
setToB() // i.e: datasource.next("b")
datasource.subscribe(val => val.shouldEqual("b"))

Related

Dependency Variable Doesnt Exist

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.

Navigation Unit Testing in MvvmCross

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);

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.

How to make a unit test in meteor that adds a document to a collection? Mocking userId

Thank you for your help-
I'd like to know if my app successfully adds a document to the database using a unit test in Meteor. I'm using practicalmeteor:mocha and chai. The issue I'm running into is that I don't know how to mock a this.userId, it keeps telling me I'm not logged in.
it('inserts the draft agenda document into the collection', function() {
// TODO: mock document to insert into collection
// TODO: mock userId and Agenda.insert
this.userId = "Not an empty string";
console.log("before spec, changing this.userId: " + this.userId) //is "Not an empty string"
Meteor.call('createAgenda', mockAgenda, function(res) {
console.log("callback with response: " + res); //You're not logged-in. [not-logged-in]
console.log("this.userId: " + this.userId) //is undefined
}
}
see https://docs.meteor.com/api/methods.html#DDPCommon-MethodInvocation-userId for more info on user id
test runner fails to import files in client directory
MochaRunner.runServerTests: failures: 1 when meteor methods are called
I have to call the server side meteor methods that have been declared in the testing context as if I am on the client, but I can't import the client files or operate as if I'm a client
MochaRunner.runServerTests: Starting server side tests with run id R7ocZh3Qva3rExTL9 runs basically every time
This seems useful but hasn't worked for me yet https://forums.meteor.com/t/testing-methods-which-use-this-userid/2292/8
Thank you for your help, any code examples would be great.
Remarks
I wanted to post a comment but do not have enough reputation. So here are some remarks. Since you are testing on the server, you can call a Meteor method without a callback. This will result in a synchronous execution and simplify your test. Otherwise you will have to let the test know it is finished by calling the done function in your callback, see mocha docs.
Using mdg:validated-method
You can call a valited method and provide the context in which they execute using the _execute function. Below is an example taken from the todos sample project. For more examples you can take a look at their Lists and Todos tests.
it('makes a list private and updates the todos', function() {
// Check initial state is public
assert.isFalse(Lists.findOne(listId).isPrivate());
// Set up method arguments and context
const methodInvocation = {
userId
};
const args = {
listId
};
// Making the list private adds userId to the todo
makePrivate._execute(methodInvocation, args);
assertListAndTodoArePrivate();
// Making the list public removes it
makePublic._execute(methodInvocation, args);
assert.isUndefined(Todos.findOne(todoId).userId);
assert.isTrue(Todos.findOne(todoId).editableBy(userId));
});
Using standard methods
Another possiblity would be to bind the standard call function to the correct context. Note that this is just a thought and not tested.
var methodInvocation = {
userId: "some user id"
};
Meteor.call.bind(methodInvocation)('createAgenda', mockAgenda);