Categories
Testing

JavaScript Unit Test Best Practices — Test Data and Logic

Spread the love

Unit tests are very useful for checking how our app is working.

Otherwise, we run into all kinds of issues later on.

In this article, we’ll look at some best practices we should follow when writing JavaScript unit tests.

Test Middlewares in Isolation

We should test middleware in isolation so that we can test the critical parts of our app.

Middlewares are used by everything, so we should test them.

Since they’re functions, we can test them in isolation.

We can just invoke it directly.

Also, we can use node-mock-http to spy on the behavior of the middleware.

We can write:

const unitUnderTest = require("./middleware");  
const httpMocks = require("node-mocks-http");  
  
test("should return http status 403 when request header is empty", () => {  
  const request = httpMocks.createRequest({  
    method: "GET",  
    url: "/user/1",  
    headers: {  
      authentication: ""  
    }  
  });  
  const response = httpMocks.createResponse();  
  unitUnderTest(request, response);  
  expect(response.statusCode).toBe(403);  
});

We use the node-mocks-http to make our requests.

Then we can pass the request and response objects into our middleware.

And then get the response.

Measure and Refactor Using Static Analysis Tools

We should use static analysis tools to improve our code quality and keep our code maintainable.

It’s useful for detecting duplication, code complexity, and other issues.

We can use tools like Sonarqube and Code Climate to check the statically analyze our app.

Check Our Readiness for Node-Related Chaos

We should also check for issues like when the server or a process dies, or when memory is overloaded.

Speed issues are also important to check.

To regularly free up resources, we can use tools to regularly kill our app instances.

We can do performance testing to find those issues.

APM tools will also help us find them.

Avoid Global Test Fixtures and Seeds

Global test fixtures aren’t good since they’re shared between multiple tests.

We don’t want to share them between multiple tests since we want independent tests.

Tests shouldn’t start with data that have been manipulated by other pieces of code.

Therefore, we should reset the data after each test so that we can always test with clean data.

Our tests should be able to run in any order and still give us the same results.

They also keep our tests simple since they’ll be easier to trace.

For instance, we write something like:

it("should return true if we can log in with valid username and password", async () => {  
  const username = 'james';  
  const password = 'password';  
  await addUser({ username, password });  
  const result = login(username, password);  
  expect(result).to.be(true);  
});

We create a new user and then use that to log in so that we know the user that we’re testing with exists.

Frontend Testing

Front end testing is also important.

Separate UI from Functionality

We should test UI separately from functionality.

When we’re testing component logic, then UI becomes the noise that should be extracted.

This way, our tests can focus on only manipulating data.

UI can be tested separately.

We can disable animation and only check data in tests.

Conclusion

We can separate our logic tests with our UI tests.

Also, we test middleware in isolation.

Data should also be created from scratch for each test.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *