1.4.0 • Published 7 years ago

jpexmocks v1.4.0

Weekly downloads
-
License
ISC
Repository
-
Last release
7 years ago

Jpex Mocks

Mocking Library for Jpex

Build Status npm version Code Climate Test Coverage

This is intended to be used when unit testing using the Jpex class framework. It adds several extra features to your classes so that you can easily mock out and test your classes.

Usage

describe('Test Suite', function(){
  var jpex, mock, MyClass, systemUnderTest;

  beforeEach(function(){
    jpex = require('jpex');
    mock = require('jpexmocks');

    MyClass = require('./myclassdeclration'),

    mock(MyClass); // From this point, anything that extends MyClass will be mocked out

    systemUnderTest = require('./service/thingy');
  });

  afterEach(function(){
    MyClass.mock.reset(true); // Reset everthing back to a pre-mocked state
  });

  it('should test using jpexmocks', function(){
    var service;

    // Inject dependencies into the class
    MyClass.mock.inject(function(myService){
      service = myService;
      spyOn(myService, 'doSomething');
      return {
        $log : function(){}
      };
    });

    // Run functions before and after instantiating the class
    MyClass.mock.afterInvoke(function(){
      expect(this.property).toBe(true);
    });

    systemUnderTest.go();

    expect(service.doSomething).toHaveBeenCalled(); // etc.
  });
});

You can pass in a specific class to mock, otherwise it will mock the base class, meaning that every subsequent class will be mocked. Once a class had been mocked, any new classes that extend it will be tracked and automatically mocked as well.

###Mock Properties A mock object will be attached to each mocked class with a number of properties:

####children An array of classes that have inherited the class. This is direct children only.

var SubClass = MyClass.extend();

MyClass.mock.children[0] === SubClass;

####descendants An array of classes that have inherited the class or any descendant class.

var SubClass = MyClass.extend();
var SubSubClass = SubClass.extend();

MyClass.mock.children[0] === SubClass;
MyClass.mock.children[1] === SubSubClass;

####instances Any time the class is instantiated, the new instance will be added to this array.

var instance = new MyClass();

MyClass.mock.instances[0] === instance;

####get This will pull out any dependencies being used by the class so that they can be manipulated or held in memory.
Keep in mind that if you get a factory or service that is not a singleton it will be a different instance to that used when the class is instantiated. For this you will want the inject or beforeInvoke functions.

var myService = MyClass.mock.get('myService');

####set Injects a dependency into the class. The value will be injected into the class when instantiated.
The dependency will be inherited by child classes.
If the value is a function it will be treated as a factory, otherwise it is injected as a constant.

MyClass.mock.set('constant', 'bob');
MyClass.mock.set('factory', function(){
  return {};
});

####inject Inject is a combination of the get and set functions.
The function parameters will be resolved and injected. You can then return an object containing additional dependencies to inject back into the class.

MyClass.mock.inject(function(mySingletonService){
  mySingletonService.something = function(){};

  return {
    $log : function(){}
  };
});

####create
The create method is similar to the get method except that if you provide an interface, it will create a new object using the interface as a pattern.

MyClass.Register.Interface('iService', i => ({a : i.string, b : i.object, c : i.either(i.string, i.number)}));

var s = MyClass.mock.create('iService');

// s = {a : 'string 101', b : {}, c : 102}

This allows you to mock out a service without having to manually create every property it contains.
For multiple-option properties such as i.any or i.either, the property is chosen at random. For array-types, an array with a random number of rows is created.

####freeze
This creates an object using create and then freezes it against the class. This allows you to create a mock object while also ensuring it will be the same instance used by your class.

var s = MyClass.freeze('iService');

new MyClass();

// the MyClass instance will use the same instance of iService that is stored in variable s

####unset This will revert a mocked dependency back to its original form. Note that you must unset the dependency on the class it was declared on, you cannot unset an inherited dependency.

MyClass.mock.set('f1', {});
SubClass.mock.set('f2', {});

SubClass.mock.unset('f2'); // This will revert f2 back to its original factory, if there was one.

SubClass.mock.unset('f1'); // This will not do anthing, subclass will still use the mocked factory from MyClass

MyClass.mock.unset('f1'); // Now both MyClass and SubClass will revert to the original factory.

####beforeInvoke This function will be invoked immediately before a class is instantiated. The function parameters will be injected as expected, however, any factories or services will be the same instances that will be passed into the constructor.
As with inject, you can return an object containing dependencies that will be passed into the constructor.
The context (this) will be the instance.

MyClass.beforeInvoke(function(myServiceInstance){
  myServiceInstance.something = function(){};
  this.someProperty = 'mocked out';

  return {
    $log : function(){}
  };
});

####invokeAfter Much like invokeBefore, this will be called immediately after the class is instantiated.

####reset This will reset the class the class to its pre-mocked state. If deep is true, it will also reset all child classes.
Keep in mind that if you don't reset s child class that relies on a mock dependency of its parent, it will no longer find it.
It's extremely advisable to reset your mocked classes after every test.

###Predefined Factories Some predefined factories are automatically mocked out:

####Timers ($timeout, $interval, $immediate, $tick) Timeouts will not just trigger on their own and must be cleared out with the flush function.

var $timeout = MyClass.mock.get('$timeout');
var instance = new MyClass();
$timeout.flush();
expect(something).toHaveHappened();

####$promise Promises also become synchronous and will only be resolved after calling $promise.flush().
If a promise doesn't get resolved in a flush cycle, it will be checked again on the next call and so on until it is resolved.
$promise has a list of all promises that can be accessed via $promise.promises. Each promise then has a state (pending, fulfilled, rejected) and its own flush function, meaning you can flush promises individually.
Keep in mind that if you attempt to flush a promise that relies on another promise, that promise will also be flushed

var $p = MyClass.mock.get('$promise');
var instance = new MyClass();

$p.promises[0].state === 'pending' // true
$p.flush();   // or $p.promises[0].flush();
$p.promises[0].state === 'fulfilled' // true

####$log For the sake of not polluting the console during testing, all log methods are mocked out and do not log to the console. Any calls to $log will be added to the messages property.

var $log = MyClass.mock.get('$log');
var instance = new MyClass();

$log.messages.length === 1;

####$fs
The $fs factory is mocked out and made syncronous. All IO operations are made on a dummy file structure you provide. In the background this uses mock-fs to mock out Node's fs module. Use the $fs.use function to provide your mock file system. For more information about the structure of this object, see the documentation for mock-fs. As with $promise, use $fs's flush method to resolve its calls.

var $fs = MyClass.mock.get('$fs');
$fs.use({
  'lib/img/img1.png',
  'lib/img/img2.png'
});

$fs.readdir('./lib/img')
  .then(function(){})
  .catch(function(){});
$fs.flush();

// As $fs is promise-based you can also flush your methods using $promise.flush();
MyClass.mock.get('$promise').flush();

If you want to restore the original version of these factories, you can use unset to undo them individually, or unsetDefaults to restore them all.

mock(MyClass);

MyClass.mock.unsetDefaults();
1.4.0

7 years ago

1.3.1

8 years ago

1.3.0

8 years ago

1.1.0

8 years ago

1.0.2

8 years ago

1.0.1

8 years ago

1.0.0

8 years ago