Nodejs Unit Testing Urls
What is the best way to do this incrementally? Eg. Some urls must be accessed before others to populate a DB etc. Is there an idiomatic node way of unit testing?
I currently read unit test data in from a json file, then request based on that.
function urlTestFn(test){
var req = requestProperties(test);
var request = http.request(req, function(resp) {
resp.setEncoding('utf8');
resp.on(开发者_开发知识库'data',function(data) {
if(data == JSON.stringify(test.response)) {
//success
} else {
sys.puts('fail');
}
});
});
if(req.method == 'POST'){
request.write(JSON.stringify(test.postData));
}
request.end();
}
To add to Peter Lynos' advise, allow me to introduce to you the correct idea of Unit Testing. When performing unit testing, a lot of people ask the wrong question. It's not "How do I test this", but "What do I test for". In your case, you want to test your code, logic, and nothing else. This means you have to remove all external factors, which includes 3rd party libraries, npm modules, and even node.js core API modules.
Ask yourself this - can you copy your test suite and run it without having to do hours of setting up the environment? You should be able to. That's the whole point of writing unit tests - making it run in isolation to ensure that your code is correct. We call that "environment" where your code can run in isolation a "control environment", similar to the same term used in scientific circles.
Now to achieve this, you need to understand the concept of fixtures and mocks. Fixtures are there to create your control environment. It does so by creating a bunch of mock objects, where each mock object takes an input and produces an output. This way, you have exact control over all aspects of your code, and it makes it dead simple to test all kinds of stuff from DB operations to REST requests.
Finally, having understood that:
- The best test suite is one that can run in an isolated, control environment
- Fixtures are used to create that environment by providing your code with mock objects
- Mock objects take in an input and returns an output
- The 3 things above can only be achieved if you had coded your project with 100% injected dependency
Mock Objects
Assuming that in your function foo() you want to read a file's contents, here's how your mock should look like:
var FsMock = {
readFile : function readFile(path, encoding, callback) {
if (path === 'unit-test-1')
callback(null, 'This is the file contents');
else
callback(new Error('Unexpected error');
}
}
And then in your test code, you try to read the file 'unit-test-1', and it will return 'This is the file contents'.
Dependency Injection
All the above would be extremely difficult if your project is not written to have their dependencies injected externally. Right now my convention is that all modules must have a make() function which takes an object that contains all its dependencies. Here's a simple example:
var Fs = null;
var Path = null;
var TestObj = module.exports = {
make : function make(args) {
if ('undefined' === typeof args.fs)
throw new Error('Dependency: FS module needed');
if ('undefined' === typeof args.path)
throw new Error('Dependency: Path module needed');
Fs = args.fs;
Path = args.fs;
return Object.create(this);
}
}
Then you need either a factory or a DI container to build that object for your, automatically constructing its dependencies.
Only then would BDD and TDD be fun in your project. Hope this helps!
OK, a few tips. Your code doesn't seem to be using any test framework whatsoever, so look at at least using commonJS asserts or a testing framework. I prefer jasmine, but there are several good ones. Jasmine has great support for spies and asynchronous tests. As a side comment, these are not unit tests, which by definition wouldn't hit a database, these are most likely application/system tests. You might want to consider writing some pure unit tests for your server side code in addition to these system level tests that send live data through your whole stack.
On the topic of test prerequisites, generally try to make each test as independent as possible. But when total independence is not avoidable, most unit testing frameworks have a concept of a setup
/teardown
pair of functions that are called before and after each test. In jasmine, this is the beforeEach
function. Pre-loading DB objects as "fixtures" is sometimes done in the Rails community. There is also the notion of "factories". Each strategy has strengths and shortcomings. I'm not sure if there are node libraries for either factories or fixtures, but do a web search.
精彩评论