Search code examples
node.jsunit-testingmocha.jschaisinon

Confused if I should use a fake or a stub?


Quite new to unit testing. I am writing unit tests for my code using Chai+Mocha and Sinon and I am stuck at a point because I am not able to decide whether I should use a Sinon stub or a fake. I have two functions processHash and processBatch. processHash internally calls processBatch, since I have already written a test case for processBatch I don't think it makes sense to test it again when I test processHash

So when writing test cases for processHash my first opinion was to go ahead with a stub and resolve processBatch manually which I have done in the test case for processBatch since it interacts with a Redis cache and SQL db internally (third party services). Then I was reading the docs for fakes and it seems fakes are suitable for this use case, thus the confusion about what the use

Here are the functions I am working with:

const processBatch = async (hashKeys, timestamp) => {
  
  // Get data from Redis Hash
  const [detailsArr, detailsErr] = await cacheService.getMultipleFieldsFromHash(
    'user_details',
    hashKeys
  );
 

  //DB insertion
  const [insertSuccess, insertError] = await dbService.insertLogs(
    detailsArr,
    timestamp
  );

  hashKeys = [];
  return [true, null];
};

const processHash = async (key, timestamp, currentTimestamp) => {
  //get hashKeys from sorted set
  const [hashKeys, hashKeysError] = await cacheService.getDataInRange(
    key,
    0,
    -1
  );

  const batchSize = BATCH_SIZE;
  const totalKeys = hashKeys.length;
  for (let i = 0; i < totalKeys; i += batchSize) {
    const batch = hashKeys.slice(i, i + batchSize);
    const [success, error] = await processBatch(batch, timestamp);
  }
  return [true, null];
};

Test case for processBatch:

  describe('processBatch function', () => {
    it('should return success=true if it executes correctly', async () => {
      cacheServiceStub = sinon.stub();
      dbServiceStub = sinon.stub();
      cacheServiceStub.getMultipleFieldsFromHash.resolves([[], null]);
      dbServiceStub.insertLogs().resolves([true, null]);
      const [success, err] = await processBatch(hashKeys, timestamp);
      expect(success).to.be.a('boolean');
      expect(success).to.be.equal(true);
      expect(err).to.be.null;
    });
  });

Solution

  • I would go for using a stub, you are just trying to test processHash so that is the priority.

    But also I think with testing there is no hard and fast rules either. A fake might be more helpful when you want to add more complexity to your test.

    The way I personally frame it is: What am I trying to test? -> Then you go from there and your method of testing should be clear. As opposed to letting your method of testing define your test, testing is just a tool in the end.