Home > Software design >  Do I have to use Dependency Injection, if I want to write testable code?
Do I have to use Dependency Injection, if I want to write testable code?

Time:11-20

I am writing AWS Lambda code on Serverless Framework. But I'm struggling to make my code testable. My test framework of choice is jest.

At first, my project structure as follows.


import { fooService } from '../services';

export const createFooHandler: APIGatewayProxyHandlerV2 = async (event) => {
  // some validation process
  const { code, message } = async fooService.create(event.body);
  return { statusCode: code, body: JSON.stringify({message}) }
}

import * as storage from '../storage';

export const fooService = {
  create: async (json: any) => {
    const foo = Foo.parse(json)
    const result = await storage.createFoo(foo);
    // .. some process
    return { code, message };
  }
}
const db = !process.env.IS_OFFLINE
  ? new DynamoDB.DocumentClient()
  : new DynamoDB.DocumentClient({
    region: "localhost",
    endpoint: "http://localhost:8000"
  });

export async function createFoo(foo: Foo) {...}

In this structure, do I have to use DI or not in order to write testable code?

CodePudding user response:

As a general rule, no, you do not need to use dependency injection to write testable code. Dependency injection has a range of benefits, including that it makes some kinds of tests easier, but it's possible to write thorough test suites without it.

Without you specifying what kinds of tests you want to add to your code (unit tests or integration tests would take different approaches, for example) and without knowing which external dependencies need mocking, it's not possible to say for sure what other approaches you can take. Some suggestions include:

  • Use Jest to mock whichever module is supplying the code that you don't want to run as-is in your tests (i.e. intercept any calls to the database or external APIs by replacing the real method with a stub method). In your case this would be the createFoo() method. If your code does not have a method which just adds your object to the database without making other changes you need to unit test, that's usually a sign you should refactor your code.

  • Use an in-memory testing database to supply test data and then make assertions on what changed data you expect to see after the tests have run.

  • You don't appear to need this for the specific snippet you're supplying, but in case this becomes an issue later: Use Nock to intercept calls to external APIs and make assertions on what calls you expect to see, along with what data you want those calls to return.

  • Related