söndag 22 februari 2015

Is the ES6 import feature an anti-pattern?

The new version of JavaScript is currently occupying my mind. I really like the ECMAScript 6 features, and the fact that we can write code using new stuff like arrow functions, scoped variables and native modules today (by using transpilers) is quite awesome.

There is especially one of the ES6 features that I've been thinking about: importing of modules. Modules will change the way we think about JavaScript for the web. Importing a module is so easy with ES6 and the syntax is very nice, readable and clean. How do I unit test such a module?


-----------
Update: I have experimented with an alternative to the examples in this blog. Have a look at it and please share your thoughts and feedback on the different approaches to unit testing modules:
Test friendly JavaScript modules - without Dependency Injection
-----------

The import statement uses a relative url to perform the module lookup. So, can I somehow configure a "base test suite url" to load fake modules that my module under test is dependent of? Would that require me to write a lot of stubs (files)? Is it even possible, without writing a custom module loader? That's the things I have had on my mind, for a couple of days now.


See, these days I mostly think about code and don't actually write code that much. How come? I am currently enjoying life as a swedish dad on paternity leave. The days with the one year old are great. We read books, build with blocks and laugh a lot. I love it.

When he is sleeping, I catch up on coding by reading blogs (mostly one of the great posts on ES6 by Dr. Axel Rauschmayer) or watching a video tutorial (I recommend the ES6 course on Pluralsight, by Scott Allen and Joe Eames). I am learning new things, slowly, but scheduled and at a steady pace.

Tonight, just when I had finished reading a Pippi Longstocking bedtime story to our four year old son (the big brother), the background process of the brain suddenly sent me a message: keep it simple. Use dependency injection. Dave, you know this already. I think the new syntax and the new ways of writing has blinded me, made me forget about concepts I normally use when writing c# or old school JavaScript (pre ES6).

How about writing modules with dependencies injected, by exposing something like an "init" function, instead of directly importing them? That would make them testable. Something like this:


// foo.js
let message = 'My name is foo';

var foo = {
    getFoo() {
        return message;
    }
};

export default foo;


// bar.js - dependent on foo.js 
let message = '';

var bar = {
    init(obj) {
        let foo = obj.getFoo();
        message = `${foo}bar, and I am foonky`;
    },
    getBar() {
        return message;
    }
};

export default bar;


//app.js
import foo from 'modules/foo';
import bar from 'modules/bar';

// inject dependencies
bar.init(foo);

console.log(bar.getBar());


 

Please let me know what you think about it!

-----------
Update: I have experimented with an alternative to the examples in this blog. Have a look at it and please share your thoughts and feedback on the different approaches to unit testing modules:
Test friendly JavaScript modules - without Dependency Injection

-----------

8 kommentarer:

Wildhoney sa...

Dependency injection is something I've tried to tackle in my Mocktail module for ECMAScript 6 modules: https://github.com/Wildhoney/Mocktail

David Vujic sa...

Interesting, I will check it out!

Unknown sa...

Hi, David. I think that you describe very important problem of using es6 modules and I have the same 'import' problem in my project and I decided to create own IoC container.
I will be happy if my solution will useful for you.https://github.com/SRobertZ/es6ioc

David Vujic sa...

Thank you Robert. I will have a look at it!

uri sa...

Yea. Whatever happened to easy unit testing. One of the things that made Angular 1 so appealing (compared to pre-ES6 and frameworks at the time) was that it's so easy to unit test thanks to its dependency injection.

And with ES6, have we lost this? I haven't yet Googled this.

David Vujic sa...

Maybe it will be easier than we might think? If a module is loaded only once during a session, I guess it could be manipulated in a unit test. When a module is imported by the code under test, the manipulated code would be executed instead of the production version. Maybe Dependency injection is not needed? Recently, I have been learning Python that has a module system very much like ES2015. Python is also dynamic and just like JavaScript, functions and variables can easily be overwritten. That's where I got this idea from.

I guess it depends how the browser implements module loading.

Robert Sabiryanov sa...

If you going to cover your code with unit tests then you have to use DI(best way) or in worst case use libraries like proxirify to mock imported modules

David Vujic sa...

I have made some new experiments with modules, fakes and dependencies, and would like to have your feedback on this!

Here's the post: http://davidvujic.blogspot.se/2015/11/test-friendly-javascript-modules-without-depencency-injection.html