How to setup tests with Maddox

Maddox tests are data driven scenarios. These types of data driven tests can get grow messy, quickly. As with your code, when tests get messy they become harder to understand and harder to refactor which will slow down your team's velocity. This goes against the entire point of testing which is to speed up velocity. At StriveNine we have devised a way to keep your test data as clean as possible.

The follow a concept of overriding functions. For a given set of scenarios we will always execute the same functions to setup the data before each test. All data setup MUST happen directly from a function. This encapsulation makes data organization so much easier so much cleaner. When you want to change the data for a test, you need to override the function that the data exists.

Some common data driven functions we use are: 1. setupTest, setupHttpReq, setupProxyFunc1, setupProxyFunc2, etc. You would want to use a better description than setupProxyFunc1, but you get the point. At the very minimum, you should have a different function for every mocked function in your test.

Let's take an example. First it is important to note that we explicitly create our own context object and reset it before each test. Mocha does NOT reset the this context between tests. This can lead to test data leakage between tests and can lead to false positives.

  • context.setupEntryPoint - We commonly use this to set the starting point of the test and nothing else.
  • context.setupInputParams - This will setup the data that gets passed into the starting point.
    context.
  • context.setupDbProxy - This is one of our proxy calls that would have mocked out in our test. Therefore we have separate function just to define the expected inputs and outputs for this proxy call.
  • context.setupExpected - Finally we have a function to define the expected output of the function we are testing.
let context;

beforeEach(() => {
  context = {};

  context.setupEntryPoint = () => {
    context.entryPointObject = SaveDataController; // The controller of our endpoint.
    context.entryPointFunction = "save";
  };

  context.setupInputParams = () => {
    context.inputParams = {
      dataToSave: {foo: "foo"}
    };
  };

  context.setupDbProxy = () => {
    // When reusing parameters it is best practice to copy them to ensure the referenced data changes are not causing...
    // unexpected errors in your tests.  Maddox will do this for you, but it is good to make it obvious in your test.
    context.dbProxyParams = JSON.parse(JSON.stringify(context.inputParams));
    context.dbProxyResponse = {code: 200};
  };

  context.setupExpected = () => {
    context.expectedResponse = {success: true};
    context.expectedStatusCode = 200;
  };
});

Below we have an example of overriding a function. You will see that the setupInputParams and setupExpected are both defined within the 'it' block. Both of these were previously defined in a beforeEach block, but since we now want to test that the code can handle a certain checked exception, we need to alter the data that drive the test.

// Using fromPromiseScenario
// Example of overriding a function within an 'it' block to change the scenario being tested.
it("it should handle a checked exception.", function (done) {
    testContext.setupInputParams = function () {
      testContext.httpRequest = {
        params: {},
        query: {
          homeState: "IL"
        }
      };

      testContext.inputParams = [testContext.httpRequest];
    };

    testContext.setupExpected = function () {
      testContext.expectedResponse = testConstants.MissingPersonIdParam;

      testContext.expectedStatusCode = [404];
    };

    testContext.setupTest();
    testContext.setupInputParams();
    testContext.setupGetFirstName();
    testContext.setupGetMiddleName();
    testContext.setupGetLastName();
    testContext.setupExpected();

    new Scenario(this)
      .mockThisFunction("proxyInstance", "getFirstName", testContext.proxyInstance)
      .mockThisFunction("proxyInstance", "getMiddleName", testContext.proxyInstance)
      .mockThisFunction("proxyInstance", "getLastName", testContext.proxyInstance)

      .withEntryPoint(testContext.entryPointObject, testContext.entryPointFunction)
      .withInputParams(testContext.inputParams)
      
      .test(function (err, response) {
      	Maddox.compare.shouldEqual({actual: err.message, expected: testContext.expectedResponse});
        Maddox.compare.shouldEqual({actual: response, expected: undefined});
        done();
      }).catch(function (err) {
      	done(err);
    	});
  });