typegoose / mongodb-memory-server

Manage & spin up mongodb server binaries with zero(or slight) configuration for tests.
https://typegoose.github.io/mongodb-memory-server/
MIT License
2.56k stars 185 forks source link

Randomizing db names for each test #837

Closed k2xl closed 8 months ago

k2xl commented 8 months ago

Wanted to know if there were any downsides to this approach as well as what I am missing in implementing unique tests appropriately. I've been trying to optimize our test suite runtime to see how fast I can have it run through all the tests. We are using nextjs + jest + mongodb-memory-server (v 9.1.3)

Note that each test has been written to assume the db is starting from the same state.

Originally, I had on setup() for each test call a dbConnect() function which basically does a

const replSetOptions = {
          replSet: {
            count: 1,
          },

        };

global.mongoMemoryServer = await MongoMemoryReplSet.create(replSetOptions);

However, I realized that every call to MongoMemoryReplSet.create() was taking about ~125-150ms for each test. So I was thinking of alternative approaches and thought to try using a global method per recommended in the docs

// globalSetup.ts
import { MongoMemoryReplSet } from 'mongodb-memory-server';

module.exports = async () => {
  const mongoServer = await MongoMemoryReplSet.create({
    replSet: { count: 1 },
  });
  const mongoUri = mongoServer.getUri();

  // Set the Mongo URI for the tests to use
  process.env.MONGODB_TEST_URI = mongoUri;
  console.log('\nMONGODB_TEST_URI', process.env.MONGODB_TEST_URI);

  // Add mongoServer to the global config so we can tear it down later
  global.__MONGOSERVER__ = mongoServer;
};

Then in dbConnect() basically mongoose.connect to process.env.MONGODB_TEST_URI

However, the issue I had is that the db isn't actually cleared out between each run. When I tried to dropDatabase() right after connect() the issue was that parallel tests that were running would crossover on top of each other (i.e. setting maxWorkers to 2 or more)

I came up with a hack which kind of works (though I get sometimes flaky port is in use as well as random test timeouts)

uri = process.env.MONGODB_TEST_URI;
        // now set the uri to point to a randomally generated database name
        // this is so that we can run tests in parallel
        const randomDbName = 't_' + new Types.ObjectId().toString(); // objectId should be unique between tests since it is a mix of timestamp and randomness...

        uri = uri.replace('/?', '/' + randomDbName + '?');
...
 // later ... mongoose.connect(uri as string, options).then((mongoose) => { ...

Basically the idea is that each test gets their own 'database' to test with... So they don't overlap with each other. The good news is that the tests definitely run faster now (a decent ~15% off our test suite time) -

However, as I mentioned I still sometimes (like 1/6 times maybe) get random tests that just... "hang" and timeout. So I feel that I missed doing this the correct way.