Maddox provides a simple way to rapidly unit test complex success and failure scenarios which can be driven by responses of mocked external dependencies.
npm install maddoxMaddox allows you to test all of your functional business requirements
and test performance, from end to end without hitting external dependencies.
Perfect for unit testing a service in a Micro Services or a Service Oriented
Architecture (SOA) environment.





1. Testing a Service - ./spec/unit/http-req-unit-test
2. Testing a library - https://github.com/corybill/Preconditions/tree/master/spec
3. Testing a library - https://github.com/corybill/Optional/tree/master/spec
const Maddox = require("maddox");Maddox.constants.IgnoreParam
Maddox.constants.EmptyResult
Maddox.constants.EmptyParameters
``1. IgnoreParam - If you replace a parameter within a 'shouldBeCalledWith' (or any of its variants) function call, then
that parameter will not validated.
2. EmptyResult - When your mocked function doesn't have a return value, you can use the EmptyResult constant instead of
passing in undefined.
2. EmptyParameters - When your mocked function has no expected parameters, you can use the EmptyParameters constant instead
of saying empty array.
new Scenario(this) // Create a new Scenario
.mockThisFunction("ProxyClass", "getFirstName", ProxyClass) // Mock ProxyClass.getFirstName
.mockThisFunction("ProxyClass", "getMiddleName", ProxyClass) // Mock ProxyClass.getMiddleName
.mockThisFunction("ProxyClass", "getLastName", ProxyClass) // Mock ProxyClass.getLastName.withEntryPoint(Controller, "read") // Declare Controller.read to be the entry point for the test
.withHttpRequest(httpRequestParams) // Use the object 'httpRequestParams' as the input into the Controller
// NOTE: The HTTP Response Object is created by Maddox and passed in automatically..resShouldBeCalledWith("send", expectedResponse) // Test that res.send is called with the same parameters that are defined in 'expectedResponse'
.resShouldBeCalledWith("status", expectedStatusCode) // Test that res.status is called with the same parameters that are defined in 'expectedStatusCode'
.resDoesReturnSelf("status") // Allow Express's expected chainable call res.status().send().shouldBeCalledWith("ProxyClass", "getFirstName", getFirstName1Params) // Test that the first call to ProxyClass.getFirstName is called with the same parameters that are defined in 'getFirstName1Params'
.doesReturnWithPromise("ProxyClass", "getFirstName", getFirstName1Result) // When ProxyClass.getFirstName is called for the first time, return 'getFirstName1Result' using Promise A+ protocol.shouldBeCalledWith("ProxyClass", "getFirstName", getFirstName2Params) // Test that the second call to ProxyClass.getFirstName is called with the same parameters that are defined in 'getFirstName2Params'
.doesReturnWithPromise("ProxyClass", "getFirstName", getFirstName2Result) // When ProxyClass.getFirstName is called for the second time, return 'getFirstName2Result' using Promise A+ protocol.shouldBeCalledWith("ProxyClass", "getMiddleName", getMiddleNameParams) // Test that the first call to ProxyClass.getMiddleName is called with the same parameters that are defined in 'getMiddleNameParams'
.doesReturn("ProxyClass", "getMiddleName", getMiddleNameResult) // When ProxyClass.getMiddleName is called for the first time, return 'getMiddleNameResult' synchronously.shouldBeCalledWith("ProxyClass", "getLastName", getLastNameParams) // Test that the first call to ProxyClass.getLastName is called with the same parameters that are defined in 'getLastNameParams'
.doesReturnWithCallback("ProxyClass", "getLastName", getLastNameResult) // When ProxyClass.getLastName is called for the first time, return 'getLastNameResult' using the callback paradigm. i.e. callback(err, result).test(done); // Executes the test. Up to this point, we have only build out the test context. No tests are executed until the test function is called.
// NOTE: All scenarios are asynchronous. Ensure that that 'done' function is passed in or executed by you.
mockName {String}* - This is the key for the mock. It will be used again in other functions and is used in Maddox to keep track of mocks.
funcName {String}* - The name of the function to be mocked.
object {Object}* - The object that contains the function to be mocked.
returns {Scenario}*
**
A common use case for using this function, is if you want to execute a set of code asynchronously but you don't care about the result. For Example: Let's say you want to call an HTTP endpoint to execute some code, but you want the HTTP endpoint to provide an immediate acknowledgement. In other words, you want to end the HTTP Request without waiting for the code behind the Http endpoint to be finished. Even though you want the HTTP request to finish immediately, you still want to test that the other mocks are called with the expected parameters. Normally when using the HttpReqScenario, your finisher function is automatically assigned within Maddox. Often the finisher function will be res.send, because that is the function that is commonly used to finish Http Requests via Express. This function will now tell Maddox that the execution is complete, and that Maddox can begin testing the mocks. By setting a finisher function, you are now telling Maddox to wait until finisher function has been executed before beginning to test the mocks.
As always, there are detailed examples in the unit tests of Maddox to see how this can be used. But I will also be publishing specific examples of this use case since it isn't that common.
mockName {String}* - This is the key for the mock. It will be used again in other functions and is used in Maddox to keep track of mocks.
funcName {String}* - The name of the function to be mocked.
[iteration] {Number}* - Defaults to 0. The finisher function will be executed the nth time this mocked proxy function is executed. Iterations start at 0. So if you want the finisher function to called on the second time a mocked proxy is called, then you would pass in 1.
returns {Scenario}*
**
entryPointObject {Object}* - The object to start the test from.
entryPointFunction {String}* - The function within the object to start the test from.
returns {Scenario}*
**
inputParamsIn {Array}* - Array of parameters. The first function parameter goes into index 0 and the nth parameter goes into index n.
returns {Scenario}*
**
Ordering matters when defining these expectations. If your function is called 3 times, Maddox will compare the first set of actual parameters to the first set of defined expected parameters and so on.
If your function takes a callback you should NOT add this to the params array. The callback will be automatically validated during execution when you use 'doesReturnWithCallback'.
mockName {String}* - This is the key for the mock. It should match the key from 'mockThisFunction'.
funcName {String}* - The name of the function to be mocked. Should match the name from 'mockThisFunction'.
params {Array}* - An array of expected parameters. First parameter of the function goes in index 0 and the nth parameter of the function goes into index n.
returns {Scenario}*
**
mockName {String}* - This is the key for the mock. It should match the key from 'mockThisFunction'.
funcName {String}* - The name of the function to be mocked. Should match the name from 'mockThisFunction'.
params {Array}* - An array of expected parameters. First parameter of the function goes in index 0 and the nth parameter of the function goes into index n.
returns {Scenario}*
**
I was hesitant to add this functionality as it can easily be abused. That being said, there are some valid use cases but you should always think twice before using this function as you are essentially saying that you do not care about testing this mock.
mockName {String}* - This is the key for the mock. It should match the key from 'mockThisFunction'.
funcName {String}* - The name of the function to be mocked. Should match the name from 'mockThisFunction'.
returns {Scenario}*
**
Every 'shouldBeCalledWith' or any of its variants need to be matched with a 'doesReturn' or one of its variants. Why? For every mocked function, we test that it is called with the expected, and then return something from the mocked function to continue driving the scenario through your code.
Ordering matters when defining the response from mocked functions. The first time your mock is called, Maddox will return the response of the first defined response from 'doesReturn' or one of its variants.
mockName {String}* - This is the key for the mock. It should match the key from 'mockThisFunction'.
funcName {String}* - The name of the function to be mocked. Should match the name from 'mockThisFunction'.
dataToReturn {Any}* - The data that will be returned when this mocked function is executed.
returns {Scenario}*
**
mockName {String}* - This is the key for the mock. It should match the key from 'mockThisFunction'.
funcName {String}* - The name of the function to be mocked. Should match the name from 'mockThisFunction'.
dataToReturn {Any}* - The data that will be returned when this mocked function is executed.
returns {Scenario}*
**
Every 'shouldBeCalledWith' or any of its variants need to be matched with a 'doesReturn' or one of its variants. Why? For every mocked function, we test that it is called with the expected, and then return something from the mocked function to continue driving the scenario through your code.
Ordering matters when defining the response from mocked functions. The first time your mock is called, Maddox will return the response of the first defined response from 'doesReturn' or one of its variants.
mockName {String}* - This is the key for the mock. It should match the key from 'mockThisFunction'.
funcName {String}* - The name of the function to be mocked. Should match the name from 'mockThisFunction'.
dataToReturn {Any}* - The data that will be returned when this mocked function is executed. This data will be available in the next step of your promise chain.
returns {Scenario}*
**
mockName {String}* - This is the key for the mock. It should match the key from 'mockThisFunction'.
funcName {String}* - The name of the function to be mocked. Should match the name from 'mockThisFunction'.
dataToReturn {Any}* - The data that will be returned when this mocked function is executed. This data will be available in the next step of your promise chain.
returns {Scenario}*
**
Maddox currently enforces a common paradigm for having the callback function be the last parameter. If you have a function that expects a callback, the callback must be the last parameter. Maddox will grab the callback from the last parameter and execute it with the provided dataToReturn.
The dataToReturn property for 'doesReturnWithCallback' needs to be an array to allow any any number parameters to be added in the callback function.
Every 'shouldBeCalledWith' or any of its variants need to be matched with a 'doesReturn' or one of its variants. Why? For every mocked function, we test that it is called with the expected, and then return something from the mocked function to continue driving the scenario through your code.
Ordering matters when defining the response from mocked functions. The first time your mock is called, Maddox will return the response of the first defined response from 'doesReturn' or one of its variants.
mockName {String}* - This is the key for the mock. It should match the key from 'mockThisFunction'.
funcName {String}* - The name of the function to be mocked. Should match the name from 'mockThisFunction'.
dataToReturn {Array}* - An array of parameters that will be applied (.apply) to the provided callback function.
returns {Scenario}*
**
Maddox currently enforces a common paradigm for having the callback function be the last parameter. If you have a function that expects a callback, the callback must be the last parameter. Maddox will grab the callback from the last parameter and execute it with the provided dataToReturn.
The dataToReturn property for 'doesReturnWithCallback' needs to be an array to allow any any number parameters to be added in the callback function.
mockName {String}* - This is the key for the mock. It should match the key from 'mockThisFunction'.
funcName {String}* - The name of the function to be mocked. Should match the name from 'mockThisFunction'.
dataToReturn {Array}* - An array of parameters that will be applied (.apply) to the provided callback function.
returns {Scenario}*
**
mockName {String}* - This is the key for the mock. It should match the key from 'mockThisFunction'.
funcName {String}* - The name of the function to be mocked. Should match the name from 'mockThisFunction'.
dataToReturn {Error}* - The Error object to be thrown.
returns {Scenario}*
**
mockName {String}* - This is the key for the mock. It should match the key from 'mockThisFunction'.
funcName {String}* - The name of the function to be mocked. Should match the name from 'mockThisFunction'.
dataToReturn {Error}* - The Error object to be rejected.
returns {Scenario}*
**
Maddox currently enforces a common paradigm for having the callback function be the last parameter. If you have a function that expects a callback, the callback must be the last parameter. Maddox will grab the callback from the last parameter and execute it with the provided dataToReturn.
This is a variant of 'doesReturn'. It defines what to return from a mocked function during a failure scenario that returns a promise. To force the error scenario, the mocked function will throw the dataToReturn causing the first catch block to be invoked in your promise chain. Best practice dictates that you only throw Javascript Error objects. Therefore, you should be providing a Node Error object in the dataToReturn property.
mockName {String}* - This is the key for the mock. It should match the key from 'mockThisFunction'.
funcName {String}* - The name of the function to be mocked. Should match the name from 'mockThisFunction'.
dataToReturn {Error}* - The Error object to be passed into .
returns {Scenario}*
**
**
If testing the HttpReqScenario, Maddox call into the controller function using your input params as the request and mocking out the response for you. When a response finishing function (i.e. send, json, end, etc) is called on the response object, Maddox will begin validating the request. It will first test that all functions mocked on the response were called with the expected values. Next it will test that all of mocked functions were called with the expected parameters. And finally it will call function that was the parameter for the test function. Usually for the HttpReqScenario, you can just pass in the 'done' function from your testing framework.
testable {Function}* - A function to test or to end the test. This function will be called with two parameters, err and result. In other words, 'testable(err, result)'.
returns {Promise} - Nothing gets resolved on a successful resolution of this promise chain. But you can use the promise to handle errors thrown from the 'test' function to ensure you do not allow false positives.*
**
request {Object}* - An object representing the structure of a Node HttpRequest. Most common things to add are 'body', 'params', 'query', etc. But you can put anything you'd like into this object.
returns {Scenario}*
**
funcName {String}* - The name of the function to be mocked on the HttpResponse object.
params {Object}* - An object representing an HttpRequest object.
returns {HttpReqScenario}*
**
funcName {String}* - The name of the function to be mocked. Should match the name from 'mockThisFunction'.
params {Array}* - An array of expected parameters. First parameter of the function goes in index 0 and the nth parameter of the function goes into index n.
returns {HttpReqScenario}*
**
In Express, you use the following syntax for for setting a header 'res.set("headerKey", "headerValue");'.
headerName {String}* - The name of the header. i.e. The key.
headerValue {String}* - The value of the header.
[funcName] {String}* - Defaults to Expresses .set function.
returns {HttpReqScenario}*
**
I was hesitant to add this functionality as it can easily be abused. That being said, there are some valid use cases but you should always think twice before using this function as you are essentially saying that you do not care about testing this mock.
mockName {String}* - This is the key for the mock. It should match the key from 'mockThisFunction'.
funcName {String}* - The name of the function to be mocked. Should match the name from 'mockThisFunction'.
returns {HttpReqScenario}*
**
Ordering matters when defining the response from mocked functions. The first time your mock is called, Maddox will return the response of the first defined response from 'doesReturn' or one of its variants.
mockName {String}* - This is the key for the mock. It should match the key from 'mockThisFunction'.
funcName {String}* - The name of the function to be mocked. Should match the name from 'mockThisFunction'.
dataToReturn {Any}* - The data that will be returned when this mocked function is executed.
returns {Scenario}*
**
mockName {String}* - This is the key for the mock. It should match the key from 'mockThisFunction'.
funcName {String}* - The name of the function to be mocked. Should match the name from 'mockThisFunction'.
dataToReturn {Any}* - The data that will be returned when this mocked function is executed.
returns {Scenario}*
**
**
actual {Object}* - The actual value for comparison.
expected {Object}* - The expected value for comparison.
[message] {String}* - The message added to the Errr if the comparison fails.
[context] {Object}* - Holds different configuration options.
[context.noDebug] {Boolean}* - If set to true, Maddox will not append the actual and expected in the stacktrace. Defaults to false.
returns nothing*
**
value {Object}* - The value for comparison. If this value is truthy then the test will pass.
[message] {String}* - The message added to the Errr if the comparison fails.
[context] {Object}* - Holds different configuration options.
[context.noDebug] {Boolean}* - If set to true, Maddox will not append debug info in the stacktrace. Defaults to false.
returns nothing*
**
value {Object}* - The value for comparison. If this value is falsey then the test will pass.
[message] {String}* - The message added to the Errr if the comparison fails.
[context] {Object}* - Holds different configuration options.
[context.noDebug] {Boolean}* - If set to true, Maddox will not append debug info in the stacktrace. Defaults to false.
returns nothing*
**
context {Object}* - A context object holding 3 main parameters: actual, expected, and message. Also holds configuration params.
context.actual {Object}* - The actual value for comparison.
context.expected {Object}* - The expected value for comparison.
[context.message] {String}* - The message added to the Errr if the comparison fails.
[context.noDebug] {Boolean}* - If set to true, Maddox will not append the actual and expected in the stacktrace. Defaults to false.
returns nothing*
**
context {Object}* - A context object holding 2 main parameters: value and message. Also holds configuration params.
context.value {Object}* - The value for comparison. If this value is truthy then the test will pass.
[context.message] {String}* - The message added to the Errr if the comparison fails.
[context.noDebug] {Boolean}* - If set to true, Maddox will not append debug info in the stacktrace. Defaults to false.
returns nothing*
**
context {Object}* - A context object holding 2 main parameters: value and message. Also holds configuration params.
context.value {Object}* - The value for comparison. If this value is falsey then the test will pass.
[context.message] {String}* - The message added to the Errr if the comparison fails.
[context.noDebug] {Boolean}* - If set to true, Maddox will not append debug info in the stacktrace. Defaults to false.
returns nothing*
**
context {Object}* - A context object holding 2 main parameters: value and message. Also holds configuration params.
context.value {Object}* - The value for comparison. If this value is truthy then the test will pass.
[context.message] {String}* - The message added to the Errr if the comparison fails.
[context.noDebug] {Boolean}* - If set to true, Maddox will not append debug info in the stacktrace. Defaults to false.
returns nothing*
**
[message] {String}* - Define the message to fail with. The default message is: 'It should be impossible to reach this code.'.
returns nothing*
**