electrolyte icon indicating copy to clipboard operation
electrolyte copied to clipboard

Question: How to use Electrolyte IoC in tests?

Open ssljivic opened this issue 9 years ago • 2 comments

Is there a way to somehow reset.reload container? That would be useful since, what I planned to do (in absence of a better idea) is to mock/modify/stub some of the injected dependencies for the purpose of a test. However, I want a clean state for the next test (usually I would reset container in beforeEach()).

If this is not the right way, can someone point me to the right direction? Electrolyte is great, but I could not find good example how to use it in tests and how to mock deps.

Another good thing would be the ability to manually add/override some component in the container - again for test mocking purposes (something similar to Angular's $provide...)

ssljivic avatar Feb 23 '16 21:02 ssljivic

You can create custom container for each test case.

const IoC = require('electrolyte');

describe('myModule', function() {
    let container;

    beforeEach(function() {
        container = new IoC.Container();
        container.use(IoC.dir('app/myContainerFolder'));
        myModule = container.create('myModule');
    });
});

... and override modules with mocks like

container.use(function(id) {
    if (id === 'myDep') {
        myDepMock['@literal'] = true;
        return myDepMock;
    }
});

...or create something like this...

xduseko avatar May 16 '16 08:05 xduseko

IoC.Container().use uses a hierarchy – the last .use(...) is the first one to be checked for an object. So while using a different container for each test is one option, adding extra .use(...)s during tests is another.

Assuming you have src/models which stores your UserModel, ExampleModel, etc., you can have test/mocks include mocks for ExampleModel; or if you need more refined control test/mocks/ExampleModel will be a directory containing only the ExampleModel mock.

This allows you to use the following in your main application:

const IoC = require('electrolyte');
const container = IoC.Container();
container.use(IoC.node_modules());
container.use(IoC.dir('src/models'));
container.use(IoC.dir('src/controllers'));
container.use(IoC.dir('src/routes'));
// ...

And then in your test set-up, you can either manually instantiate individual models with mocks (semi-ugly):

// IoC code above...
const ExampleController = require('src/controllers/ExampleModel');
const ExampleModelMock = require('test/mocks/ExampleModel');
let controller = new ExampleController(new ExampleModelMock(), IoC.create('UserModel'));

Or, add an extra .use(...) so that a mock called ExampleModel is resolved:

// IoC code above...
container.use(IoC.dir('test/mocks'));  // mocks must be named exactly the same as the original object
let controller = IoC.create('ExampleController');

Feature Request:

Although I would like to see some method that allows hot-swapping of different mocks. Perhaps something similar to

// in your tests bootstrap file:
container.use(IoC.dir('test/mocks'));  // mocks suffixed with 'Mock' such as 'ExampleModelMock'

// in a particular test:
let controller = IoC.create('ExampleController', {
  // override the `ExampleModel` with a mock
  'ExampleModel': IoC.create('ExampleModelMock')
});

hoxxep avatar May 16 '16 14:05 hoxxep