I want to make integration tests in my node app. I have express endpoint, for example: POST: /users. This endpoint runs the User service to create a new user.
So I have the following dir structure:
routes
users
create.js // router.post('/users', ...);
services
users
create.js // actual user creation implementation
As you can see, the routes/users/create.js runs the services/users/create.js which does just anything and returns a response to the router and then the router sends back to the client.
I want to test it. As I said, should I test the route (using supertest or a kind) or the service or both?
As you may know there are three different types of tests:
Integration
End-to-end
Unit
Testing your router will cause the invocation of the other functions in your router and it'll go all the way through the path of calling everything! this is only in a scenario where you use everything as is and don't create mock or spy for those functions.
Testing a router is more of an End-To-End testing than unit testing.
If you want to use any sort of fakes (mock, spy) then you have to be careful since not always you're allowed to do it ( if you basically have an unmanaged dependency like a shared database between more than one service. you can only use fakes in this scenario ). other than that using mocks brings test fragility and violates resistance to regression (how much code/branches you've covered) and resistance to refactoring (how likely it is if you change any code your test breaks).
So testing routers is basically integration testing, not unit testing and is possible!
Related
I'm developing APIs for social networking web application for learning perspective. When I started to write test cases I stuck around how to organize/write test cases.I'm initially proceeding like this:
First setup global data base initialization:
I need some users' auth tokens to test my routes so I decide to set up these information at global context. Also there are other information that also need to setup at global context so I'm setting that too.
Then for each route:
I start to write test cases and thought that I would write test cases in
such a way that each route test cases would be independent to each other.
and after completing all test suites:
I thought that I would clean up my data base.
The problems with this approach I'm facing are:
Say I want to test four routes named /users , /users/:id/my_invites , /send_invites, /response_invites. And further suppose I'm only interested in writing test cases for GET request and response for /users , /users/:id/invites and POSTing data in the case of others.
/send_invites, /response_invites definitely trigger some actions on the server side that modifies the data base state.
As we see that these routes effect the state of other routes' data say one user sends invites to another user and gets response true/false, so for that user his request was successful but how to ensure that another user actually received the invitation if we don't checking his received invitation documents(i.e through another route) in the first route test cases. Means /send_invites effects the /users/:id/my_invites .
because these routes are dependent on each others
So The questions I want to ask are:
how to write test cases for these routes so that each route would be independent ?
I tried with three dummy testing users in the global context and trying all sort of combinations for them in all test suites.My test suit presently deals with more than one routes to check 1 route true functionality.
Can anyone suggest me better solution for writing test cases for the above mentioned scenarios?
May be my question is too long or not clear. Please let me know and help me if you can.
My opinion:
First the bases EACH test case should have a fresh new state. That means that before you check one scenario, you want to flush your database and insert your new data prepared to test that case scenario. You can use a real database o mock one with data in-memory or however you prefer.
Second, each endpoint potentially affects a lot of tables in your database. So it's perfectly normal to check the state of your data, independently of the tables to check that the information is correct.
And well mocha and other test frameworks have functions that help you to do that. Like beforeEach and afterEach to set up and tear down your data before each test case.
I am developping a RESTful Node.js API (express+mongoose)
This API calls a third party Oauth API (google, facebook, whatever).
I've been quite happy setting up automated testing with mocha+chai+request so far, but I'm having trouble mocking the third party API to test the route (of my API) that calls it.
I've tried using nock, but it doesn't work for my use case.
To run my tests, I start my API (npm start), and in another tab, I start the test suite (npm test). The test suite uses request to test the API over HTTP.
Hence I think nock doesn't work here because it is mocking http in the 'test suite' process and not in the 'API' process.
I absolutely need to mock this third party call for 2 reasons:
1. I want to be able to run my test suite offline with everything running on my laptop
2. Since the third party API uses Oauth, hard coding credentials in the test suite (even for a test account) doesn't seem too easy.
I would really love not to leave this giant hole in my test coverage, so any advice would be much apreciated!
so this is how I solve my own problem. I came up with it on my own while setting up proper testing for an app for the first time so feel free to suggest improvements. Disclaimer: I use coffee script
The first step was to launch my app from another file, starter.coffee, that essentially looks like this:
# This file starts the API locally
require './test/mocks/google_mock'
require './app'
So to start my server for tests, instead of doing coffee app.coffee, I would do coffee starter.coffee.
The google_mock.coffee file mocks the Google API before the app is launched from the app.coffee file.
For that I use the nock! package.
The google_mock.coffee files looks like this:
nock = require 'nock'
# mocking up google api
googleapis = nock('https://www.googleapis.com')
.get('/userinfo/v2/me')
.reply(401)
with a lot more lines for mocking other Google api calls.
I am using LocomotiveJS to build an MVC application. I have been thinking about the type of tests I should write and am confused.
Here are the different components in the application - Models, Views, Controllers, Router and the ORM.
If I had to unit test every component, here is how I think I should approach it.
Write tests to ensure the API provided by ORM act the way I expect it to.
Unit test my Model stubbing the ORM. I provide it the stub so I do not have to rely on actual database operations in my unit test.
A Controller accesses Views and Models. A Controller's job is to get/modify the model and to respond to the client (render/redirect).
The controller's response can be tested by providing them test inputs and checking if the right response is generated (stub out render/redirect and make sure the right calls are made).
Model manipulation by the controller can be tested by stubbing out the model and ensuring the right calls are made. This feels wrong, since I am testing the implementation...
Views are just templates; the controller binds the templates with values. I could create a fake view model and bind it to the view and see if the right output is generated.
Routes just take the request and map it to the right Controller and Action. I can ensure the right routes are supported by the app by stubbing out parts of the Router and making sure a request to the router is mapped to the expected Controller/Action.
Say I change a model API now, I have to change the model test, I have to change the model stubs used by the controller test and I have to update the assertions in controller test.
This seems like overkill.
Does this rather make sense?
Do 1 and 2 as above.
3. Integration test the rest (Controller/View/Router). Here I think I should just start up my app in a test environment and use supertest to ensure the requests generate the right responses - visiting an url, I get the right content, right redirects etc.
I think it makes sense to unit test the model because it represents an interaction with a different system (data persistence). We want to make sure the bridge functions properly. Router/Controller/View interact within our own system and in very specific ways. So it seems okay to integration test that. What are your thoughts?
If you rely on integration tests, you will lose the benefits of unit tests. Your tests will run more slowly than they need to and will therefore be run less often. Your tests will not tell you where you broke something. Your tests will not exercise as much of the functionality of the application. Your tests will be only half as effective as documentation. You will not be able to TDD.
Overall, any time someone chooses to forgo unit tests in the interest of speed, they go more slowly.
I am building an app with locomotive.js, and I am looking to build my test suite using the Mocha test framework. I am also new to TDD/BDD in general, so please take that into consideration. I am curious if anyone can point me in a good direction to start testing a locomotive based app.
My biggest question would be:
How do I test a controller's actions?
Can I test an initializer?
Are there best practices around creating test request objects?
Testing controller actions
It depends on what exactly you want to test. Controller actions usually either return content, or pass (perhaps in case of errors) the request along the server stack, so testing them means using something like supertest to check for the correct responses (the supertest page also mentions how to use it together with Mocha)
Can I test an initializer?
Testing an initializer by itself is difficult, because they require to be run within the context of a LocomotiveJS application. However, you could create a test just booting up the application, which during the booting process will also run all initializers. I just added a simple Mocha-based testing framework to my Locomotive + Sequelize boilerplate project which shows how to boot the Locomotive app from within Mocha.
Are there best practices around creating test request objects?
If you mean how you can check responses to requests, look at the aforementioned supertest or perhaps mocha-headless.
How would I mock out the database in my node.js application, which in this case uses mongodb as the backend for a blog REST API ?
Sure, I could set the database to a specific testing -database, but I would still save data and not test my code only, but also the database, so I am actually not doing unit testing but integration testing.
So what should one do? Create database wrappers as a middle layer between application and db and replace the DAL when in testing?
// app.js
var express = require('express');
app = express(),
mongo = require('mongoskin'),
db = mongo.db('localhost:27017/test?auto_reconnect');
app.get('/posts/:slug', function(req, res){
db.collection('posts').findOne({slug: req.params.slug}, function (err, post) {
res.send(JSON.stringify(post), 200);
});
});
app.listen(3000);
// test.js
r = require('requestah')(3000);
describe("Does some testing", function() {
it("Fetches a blogpost by slug", function(done) {
r.get("/posts/aslug", function(res) {
expect(res.statusCode).to.equal(200);
expect(JSON.parse(res.body)["title"]).to.not.equal(null);
return done();
});
});
));
I don't think database related code can be properly tested without testing it with the database software. That's because the code you're testing is not just javascript but also the database query string. Even though in your case the queries look simple you can't rely on it being that way forever.
So any database emulation layer will necessarily implement the entire database (minus disk storage perhaps). By then you end up doing integration testing with the database emulator even though you call it unit testing. Another downside is that the database emulator may end up having a different set of bugs compared to the database and you may end up having to code for both the database emulator and the database (kind of like the situation with IE vs Firefox vs Chrome etc.).
Therefore, in my opinion, the only way to correctly test your code is to interface it with the real database.
There is a general rule of thumb when it comes to mocking which is
Don't mock anything you don't own.
If you want to mock out the database hide it behind an abstracted service layer and mock that layer. Then make sure you integration test the actual service layer.
Personally I've gone away from using mocks for testing and use them for top-to-bottom design helping me drive development from the top towards the bottom mocking out service layers as I go and then eventually implementing those layers and writing integration tests. Used as a test tool they tend to make your test very brittle and in the worst case leads to a divergence between actual behavior and mocked behavior.
I don't agree with the selected answer or other replies so far.
Wouldn't it be awesome if you could catch errors spawned by the chaotic and many times messy changes made to DB schemas and your code BEFORE it gets to QA? I bet the majority would shout heck yes!
You most certainly can and should isolate and test you DB schemas. And you don't do it based on an emulator or heavy image or recreation of you DB and machine. This is what stuff like SQLite is for just as one example. You mock it based on an in memory lightweight instance running and with static data that does not change in that in memory instance which means you are truly testing your DB in isolation and you can trust your tests as well. And obviously it's fast because it's in memory, a skeleton, and is scrapped at the end of a test run.
So yes you should and you should test the SCHEMA that is exported into a very lightweight in memory instance of whatever DB engine/runtime you are using, and that along with adding a very small amount of static data becomes your isolated mocked DB.
You export your real schemas from your real DB periodically (in an automated fashion) and import/update those into your light in memory DB instance before every push to QA and you will know instantly if any latest DB changes done by your DB admins or other developers who have changed the schema lately have broken any tests .
As for the person who replied with the "don't mock anything you don't own". I think he meant to say "don't test anything you don't own". But you DO mock things you do not own! Because those are the things not under test that need to be isolated!
This is what many test driven teams do all the time. You just have to understand the how.
My preferred approach to unit test DB code in any language is to access Mongo through a Repository abstraction (there's an example here http://iainjmitchell.com/blog/?p=884). Implementations will vary in terms of DB specific functionality exposed but by removing all the Mongo code from your own logic you're in a position to Unit Test. Simply replace the Mongo Repository implementation with a stubbed out version which is trivially easy. For instance, just store objects in a simple in-memory dictionary collection.
You'll get the benefits of unit testing your own code this way without DB dependencies but you'll still need to do integration tests against the main DB because you'll probably never be able to emulate the idiosyncrasies of the real database as others have said here. The kind of things I've found are as simple as indexing in safe mode vs without safe mode. Specifically, if you have a unique index your dummy memory implementation might honour that in all cases, but Mongo won't without safe-mode.
So whilst you'll still need to test against the DB for some operations, you'll certainly be able to unit test your own logic properly with a stubbed out Repository implementation.
The purpose of mocking is to skip the complexity and unit test own code. If you want to write e2e tests then use the db.
Writing code to setup/teardown a testing DB for unit testing is technical debt and incredibly unsatisfying.
There are mock libraries in npm:
mongo - https://www.npmjs.com/package/mongomock
mongoose - https://www.npmjs.com/package/mockgoose
If those don't support the features you need, then yes you may need to use the real thing.
I had this dilemma and chosen to work with a test DB and clean it every time the test begins. (how to drop everything: https://stackoverflow.com/a/25639377/378594)
With NPM you can even make a test script that creates the db file and cleans it up after.