how to run test in certain cases? - node.js

I'm new to TDD and I wrote a few test functions that check the sign up and deletion of the user , but before each running i go to the database and delete the user before testing the sign up and i go to the database to put a dummy user info before deletion so my question is how does this thing run in actual production environment , like every time I want to run the tests , I go to the database and make all these modification , what if user signed up with the below credentials then the test would return 200 ?? (i use jest with nodejs e2e)
describe("given user is not found", () => {
it("should return 404", async () => {
await request(app)
.post("/api/v1/auth/signIn")
.send({
email: "s#gmail.com",
password: "s",
})
.expect(404);
});
});```

Other opinions are available but here's what I'd do.
Let's assume your backend is in java. Before I wrote any code I would have a test that called the API endpoint with the same input and expected a 404.
Some will tell you to mock the database with a library like Mockito but I don't think that's necessary. For our purposes a database is nothing but a map. A map takes an id and returns an object. So make an interface that describes interactions with your database, saveUser(), loadUser() - that kind of thing. Implement the interface with your real implementation. And implement it with your test one which is just a class with those same methods and a map for actually doing real work. This is called a fake.
Your api could return a 404 if the user is not found or a 200 if it is. Your test is in the backend and its quicker than it was before because you're not hitting a real database.
As far as your example goes I really don't think you need to set anything up in the database at all. But if you absolutely must then you could have an endpoint which tears down the database setup and sets it up again, which is executed at the start of the test. Or a database image that you stand up just for the test. Both are probably overkill.

Related

Best way to write unit test for Node Rest api while working with Postgres, chai and mocha?

I am working on node js rest api in which database is Postgres and we are not using any ORM. How I am writing is as below which is hitting database for create and update
it('it should create customer', (done) => {
const payload = {
customerId: "test",
customerName: "test",
customerAddress: "Some place, NWZ"
}
chai
.request(server)
.post('/customer')
.send(payload)
.end((err, res) => {
res.should.have.status(200);
res.body.success.should.equal(true);
done();
});
});
Now I want to know that what is best way to write unit test cases ? Like
Should I write unit test cases by mocking api response excluding database query ?
Or should I write unit test case which will hit database ?
Or in any way we can mock database ? What is best way to do it ?
There is some debate regarding whether unit tests should hit database. But in general, I would say hitting a real database in testing should be categories as integration test, not unit test.
So for your question 2: I would say: no, you should not write unit test case that hit database.
Then for your question 1: yes, you should mocking api response, the library you could choose, e.g. sinon.
---- Updated ----
There is an article regarding the topic, if you are interested, please refer to the following: Hitting Real Database? Unit Test and Integration Test for RESTful API in Nodejs Environment

end to end or integration or system testing

What kind of testing is this? Is the following considered end to end testing or is it an integration testing or a system testing? If not if you can elaborate on the types of testing in context of the code example.
I'm basically calling the endpoint on localhost and asserting on the status/output.
let assert = require("assert");
let http = require("http");
describe("EndToEndTesting", function() {
describe("GET /users", function() {
it("should return list of users", function(done) {
http.request({
method: "GET",
hostname: "localhost",
port: 3000,
path: "/users"
}, function(response){
let buffers = [];
response.on("data", buffers.push.bind(buffers));
response.on("end", function(){
let body = JSON.parse(Buffer.concat(buffers).toString());
assert(response.statusCode == 200);
});
}).on("error", console.error).end();
});
}
}
Interesting question, unfortunately the answer can depend on a number of things.
Let's start with a few definitions:
End to End testing is testing the application from start to finish. I.e. a complete flow that a user would be expected to do.
Integration testing is testing a group of components together as a single item.
System testing is testing the system as a whole against the requirements.
So the first question to consider, is this test checking a complete flow that a user would be expected to achieve?
This does mean you need to define who the user is. If for example you are building an API that is then re-used by other developers your user as the author of the api will be different to the end user of the solutions integrating your api.
My best guess is that this isn't an end to end test. Looking at the test it is a web request to get a list of users. If you are building a Web UI that can list confidential information I would expect this to require the person accessing the list to be logged in. Therefore the end to end test would include logging into the system.
So, next question, what components are being tested? Hard to tell from the test code but I am guessing the data is stored in database somewhere. So yes this is an integration test as it checks the interaction between the web component and the database.
Finally, is this a system test. Probably yes as I cannot see any evidence of this not being run against the system as a whole. Also, assuming the requirement of your solution is to be able to list the users then it is testing the required functionality.
So, in this case I believe it could either be a system or an integration test. Unfortunately based on the definitions of these test types there is often an overlap where tests could be classified as either. So it's ultimately up to you whether you call it a system or an integration test.

Services should throw exceptions? (Web API)

I found similar questions but not found any good answer so I am posting it again and with more specific environment.
I am using Node.js + Express to build REST APi for my React Native app.
I am using pattern Router->Controller->Service->Database and I am not sure if I am supposed to throw specific errors from my services.
Example:
I am validating registration request.
Field validations are hapenning inside Controller (I am using ajv JSON schema validator).
Now I need to validate if user/email already exists
Am I supposed to do this from controller by calling for example service.emailExists(data.email) before calling service.createUser(data)??
Or I can let database fall on CREATE duplicate, return false from service.createUser(data) and inform user from controller that Email exists. If I do so, I am not able to inform user if there is Unspecified error inside service, because it will always return as Email exists error, even something else happens.
You can use try...catch, or if...else to handle the possibilities of errors.
This is how it worked for me. Service using express and sequelize
const { Keluhan } = require('../../models');
var getAllKeluhan = () => {
return Keluhan.findAll()
.then(data => {
if (data) {
return {
code: 200,
message: "Data Found!",
result: data
};
} else {
return {
code: 404,
message: "Data not Found!"
}
}
})
.catch(err => {
throw err;
})
}
module.exports = getAllKeluhan;
This kind of typical problem can be solved in different ways. i provide below few.
A general way of handling it to fail in Database layer and there will be a cascading of failure from database layer to service layer and then controller layer. In this case it is assumed that there is no graceful failure and in this case, people just broadcast a generic failure. All the errors and exceptions are reported in a log.
The another approach is to make a failure at the service layer itself if the email id already exists in the cache without connecting to database. It seems to be a good approach as long as there is a good synchronization between database and the cache layer.
Another approach would be a proactive failure where once the user enters the email id and makes a tab out in UI, you can connect to database to validate through a service.
Sometimes, it is also thought that let the user enters everything in the UI screen and let us validate at the end.
As far as design is concerned, I think approach should be given by the functional team who propose the idea. Technically, all the approaches are possible.
The most important thing here is to grab the error or exception in the controller and propagate as a bad request. It means user should be notified whether email id already exists or not.
Finally, you can think of the design like Fail-Safe or Fail-Fast as per your requirements.

Unit testing for loopback model

I have a Loopback API with a model Student.
How do I write unit tests for the node API methods of the Student model without calling the REST API? I can't find any documentation or examples for testing the model through node API itself.
Can anyone please help?
Example with testing the count method
// With this test file located in ./test/thistest.js
var app = require('../server');
describe('Student node api', function(){
it('counts initially 0 student', function(cb){
app.models.Student.count({}, function(err, count){
assert.deepEqual(count, 0);
});
});
});
This way you can test the node API, without calling the REST API.
However, for built-in methods, this stuff is already tested by strongloop so should pretty useless to test the node API. But for remote (=custom) methods it can still be interesting.
EDIT:
The reason why this way of doing things is not explicited is because ultimately, you will need to test your complete REST API to ensure that not only the node API works as expected, but also that ACLs are properly configured, return codes, etc. So in the end, you end up writing 2 different tests for the same thing, which is a waste of time. (Unless you like to write tests :)

Should I use a server method or Collection.insert() to insert a record using Meteor?

I'm trying to decide between two methods for inserting a new document to a collection from the client using Meteor.js. Call a Server Method or using the db API directly.
So, I can either access the db api directly on the client:
MyCollection.insert(doc)
Or, I can create a new Server Method (under the /server dir):
Meteor.methods({
createNew: function(doc) {
check(doc, etc)
var id = MyCollection.insert(doc);
return project_id;
}
});
And then call it from the client like this:
Meteor.call('createNew', doc, function(error, result){
// Carry on
});
Both work but as far as I can see from testing, I only benefit from latency compensation (the local cache updating and showing on the screen before the server responds) if I hit the db api directly, not if I use a Server Method, so my preference is for doing things this way. But I also get the impression the most secure approach is to use a Method on the server (mainly because Emily Stark gave it as an example in her video here) but then the db api is available on the client no matter what so why would a Server Method be better?
I've seen both approaches taken when reading source code elsewhere so I'm stumped.
Note. In both cases I have suitable Allow/Deny rules in place:
MyCollection.allow({
insert: function(userId, project){
return isAllowedTo.createDoc(userId, doc);
},
update: function(userId, doc){
return isAllowedTo.editDoc(userId, doc);
},
remove: function(userId, doc){
return isAllowedTo.removeDoc(userId, doc);
}
});
In short: Which is recommended and why?
The problem was that I had the method declarations under the /server folder, so they were not available to the client and this broke latency compensation (where the client creates stubs of these methods to simulate the action but in my case could not because it couldn't see them). After moving them out of this folder I am able to use Server Methods in a clean, safe and latency-compensated manner (even with all my Allow/Deny rules set to false - they do nothing and only apply to direct db api access from the client, not server).
In short: don't use the db api on the client or allow/deny rules on the server, forget they ever existed and just write Server Methods, make sure they're accessible to both client and server, and use these for crud instead.

Resources