Test Doubles

From Logic Wiki
Jump to: navigation, search


Test doubles are objects that are used in unit tests as replacements to the real production system collaborators.

Types of Test Doubles

Dummy

Objects that can be passed around as necessary but do not have any type of test implementation and should never be used.

Fake

These object generally have a simplified functional implementation of a particular interface that is adequate for testing but not for production.

Stub

These objects provide implementations with canned answers that are suitable for the test.

Spies

These objects provide implementations that record the values that were passed in so they can be used by the test.

Mocks

These objects are pre-programmed to expect specific calls and parameters and can throw exceptions when necessary.

Mock Frameworks

Most mock frameworks provide easy ways for automatically creating any of these types of test doubles at runtime

Sinon.JS

  • Javascript Mocking Framework
  • Works in NodeJS and a web browser
  • Works well with Mocha and Chai

Creating a Spy

  • The most basic test double provided by Sinon is the spy.
  • A spy is created by calling the sinon.spy method.
  • A spy keeps track of:
    • How many times a function was called.
    • What parameters were passed to the function.
it(‘tests spies’, function(){
 var callback = sinon.spy();
 prodFunction(callback);
 expect(callback).to.have.
 been.called();
});

Method Wrapping Spy

  • Spies can be created in two fashions: either anonymous or wrapping a particular method.
  • Anonymous spies are used to create fake functions that need to be spied on during testing.
  • Method wrapping spies are created on existing functions such as class methods
//Method Wrapping Spy
it(‘tests spies’, function(){
 var tc = new TestClass();
 sinon.spy(tc, “testFunc”);
 tc.testFunc();
 expect(tc.testFunc).to.have.
 been.called();
});

Spy API

Sinon provides an extensive API for testing calls made to a spy. For example:

  • spy.callCount - The number of times the spy was called.
  • spy.called - True if the spy was called at least once.
  • spy.calledWith(arg1, arg2, …) - Spy was called with the specified arguments (and possibly others)
  • spy.returnValues - Array of return values made from the spied on function for each call to the function.
  • Complete API available at: https://sinonjs.org/releases/v6.1.5/spies/
  • spy.threw - The spy threw an exception at least once.

Complete API available at: https://sinonjs.org/releases/v6.1.5/spies/

Sinon Stubs

  • Sinon also provides an API for implementing stub test doubles.
  • Stubs are like spies in that they can be anonymous or wrap existing functions.
  • Stubs support the full Spy testing API. Stubs are different from spies in that they do NOT call the wrapped function
  • Stubs allow you to modify the behavior of the stubbed function call.
//Sinon Stub
it(‘tests stub’, function(){
 var tc = new TestClass();
 sinon.stub(tc, “testFunc”);
 testCall(tc)
 expect(tc.testFunc).to.have.
 been.called();
});

Sinon Mocks

  • Sinon also provides an API for creating mock objects.
  • Sinon mocks provide all the capabilities of Sinon spies and stubs with the addition of preprogrammed expectations.
  • A mock will verify that the specified expectations have occurred and if not will fail the test.
// Sinon Mocks
it(‘tests mock’, function(){
 var tc = new TestClass();
 var mock = sinon.mock(tc);
 mock.expects(‘func’).once();
 testCall(tc)
 mock.verify();
});

Sinon Mocks Expectations

  • Sinon Mocks provide an extensive API of expectations that can be set. For example:
    • expectation.atLeast - The mock was called at least the specified number of times.
    • expectation.never - Verifies the mock was never called.
    • expectation.once - Verifies the mock was called once.
    • expectation.withArgs - The mock was called with the specified arguments and possibly others.
    • expectation.on(obj) - The mock was called with the specified object as “this”.

Complete API available at: https://sinonjs.org/releases/v6.1.5/mocks/

Sinon Cleanup

  • Sinon creates all of its test doubles in a sandbox.
  • Although you can create your own sandbox you will typically use Sinon’s default sandbox.
  • After each test the sandbox needs to be reset to clear out all the test doubles that were created by calling the sinon.restore method.
// Sinon Cleanup
afterEach(()=>{
 sinon.restore();
});

Sinon-Chai

  • The Sinon-Chai library continues the BDD style expectations provide by Chai when using Sinon test doubles.
  • Sinon-Chai provides an API that on your mocks that mimics the Chai expect and should APIs.
  • This helps ensure your unit tests consistently follow the Chai BDD style of specifying expectations.
//Method Wrapping Spy
it(‘tests spies’, function(){
 var tc = new TestClass();
 sinon.spy(tc, “testFunc”);
 tc.testFunc();
 tc.should.have.been.called();
});