Unit testing a class that requires dependencies


#1

I want to create some tests that test a method on a class. I don’t want to (can’t) create mocks as this is certainly more integration testing.

My class requires eventAggregator, taskQueue, ValidationControllerFactory and a few other project specific classes to be injected into the constructor.

All of the examples I came across seem to be relying on mock classes. I need the magic of Aurelia dependency injection, is it possible? If so can someone give me an example

Thanks


#2

Guess your class is not an ui component (StageComponent can handle DI injection for it).

Try:

import {Container} from 'aurelia-dependency-injection';
const container = new Container();

// optional, if need something special
// container.registerInstance(...);
// container.registerTransient(...);
// container.registerSingleton(...);

// this will honour injections.
const instance = container.get(YourClass); 

#3

I usually just create mocks on the fly in my unit test. Dynamic languages like Typescript/Javascript really makes unit testing and mocking incredible simple:

const ea = {} as EventAggregator;
const tq = {} as TaskQueue;
const sut = new YourClass(ea, tq);

Now, if the component you’re testing actually uses any of these mocks, it’s simple to stub out any method calls on them;

ea.publish = (event: any, data?: any) => { return; };

Or the I18N plugin;

const i18n = {} as I18N;
i18n.tr = (key: string) => key;

#4

Thanks, this is what I was hoping for. For my case would i have to register an instance of EventAggregator and TaskQueue and the others, or will the container magically find that stuff?


#5

Thanks, but I can’t use mocks, i need to test actual implementations. I know it’s not a “unit” test, but it’s the kind of testing I need.


#6

You don’t have to register any instance, they are totally optional api calls. By default, DI uses singleton for any class.

For instance, EA is using this default behavior to ensure everyone use the same EA instance (so pub/sub can work).

The default singleton behavior ensures multiple calls container.get(YourClass) always return exactly same instance.


#7

Thanks, that’s how i was hoping it would work since there is no container setup. I’m used to Unity in C# where you have to build up the container.


#8

Is there a way to register a plugin, like aurelia-validation?

https://stackoverflow.com/questions/40171563/how-to-load-an-aurelia-plugin-in-karma. Since I’m not doing a UI component, not sure i can/want to do this


#9

Plugin is not controlled by DI.

You injection should be fine without any explicit DI setup since you don’t use any aurelia-validation view layer.


#11

I’m definitely getting this error “Did you forget to add “.plugin(‘aurelia-validation’)” to your main.js?”


#12

It sounds like even when you try to write your class without depending on aurelia, the code somehow implicitly requires Aurelia bootstrapping.

Might just be aurelia-validation, but I have no experience with it.


#13

#14

Untested. Try this to set it up.

import {configure} from 'aurelia-validation';
configure({container}); // the container you created

#15

That actually got around that error, but led to another one.
this.bindinqLanguage.parseInterpolation is not a function


#16

These are the kinds of advanced things I’d like to see in a book


#17

:slight_smile:
Rabbit hole.

Obviously {container} is not enough mock of aurelia. aurelia-validation wants more.

You’d better ask some core guy to how to use aurelia-validation out of aurelia app.


#18

This new error reminded me why I extracted aurelia-binding parser to my own package in order to make my validation generic.


#19

This pretty much sounds like you would need to wire up your Tests to start with a stagedcomponent in order to have the Aurelia Environment and Plugins setup. Later you may access the VM directly from the component to perform your tests. Take a look at the Docs specifically the custom bootstrapping sample found here https://aurelia.io/docs/testing/components#testing-custom-component-with-a-real-view-model. In there you can register the validation plugin as you would in your app with aurelia.use.plugin … Also you can access the DI container in there to override specific classes


#20

I’ll give that a go, that certainly seems like a bad way to do this. I’m concerned that the validation plugin isn’t node.js ready.

I know the validators don’t need the UI to function as I have removed all the UI rendering within the actual aurelia app and i can get proper validation results from my code.


#21

After experimenting some more, it appears Aurelia-Validation will not work in a Node.js project or my test project (At least not mine). I’m not really sure what to do at the moment as I have a lot of work tied up making validation work properly on the UI. I tried to use the server test example to configure the validation plugin, but something i’m doing in my code makes the server side validation invalid.

I guess my next step is to post an issue in the repo and hope the team responds. I need to consider abandoning the plugin and rolling something custom if there is no work around for what I need. They’ll want example code and that’s tough for me to do.