I've started refactoring my code to make it testable. One area I've found a problem is where I've mixed object construction with application logic. If I have a constructor called SomeClass which performs application logic but also instantiates another class I run in to problems when I try to test:
function SomeClass() {
//does lots of application type work
//but then also instantiates a different object
new AnotherClass();
}
Testing becomes difficult because now I need to find a way to create AnotherClass in the test environment.
I've dealt with this problem using dependency injection. So SomeClass takes an instance of AnotherClass as a parameter:
function SomeClass(anotherObj) {
}
Problem with this is as far as I can see is all this does is defer the problem to somewhere else in my application. I still have to create the anotherObj from AnotherClass somewhere else in my code.
This google testing article http://googletesting.blogspot.co.uk/2008/08/by-miko-hevery-so-you-decided-to.html suggests:
In order to have a testable code-base your application should have two
kinds of classes. The factories, these are full of the "new" operators
and are responsible for building the object graph of your application,
but don't do anything.And the application logic classes which are devoid of the "new" operator and are responsible for doing work.
This sounds exactly like my problem and the factory type pattern is what I need. So I tried something like:
function anotherClassFactory() {
return new AnotherClass();
}
function SomeClass() {
anotherClassFactory();
}
But then SomeClass still has a dependency on the factory. How do I get around this correctly?
(I'm making this a community wiki answer because I frankly think it only answers part of the question, while leaving too much unsaid. Hopefully others with more knowledge can improve it.)
But then SomeClass still has a dependency on the factory. How do I get around this correctly?
According to this article linked by the one you linked, you do it like this:
anotherclass.js:
function AnotherClass() {
}
AnotherClass.prototype.foo = function() { /* ... */ };
AnotherClass.prototype.bar = function() { /* ... */ };
AnotherClass.prototype.baz = function() { /* ... */ };
someclass.js:
function SomeClass(a) {
// ...app logic...
// Use AnotherClass instance `a`; let's say you're going to call `foo`,
// but have no use for `bar` or `baz`
a.foo();
// ...app logic...
}
someclass-test.js:
function someClass_testSomething() {
var sc = new SomeClass({
foo: function() { /* ...appropriate `foo` code for this test... */}
});
// ...test `sc`...
}
function someClass_testSomethingElse() {
// ...
}
app.js:
function buildApp() {
return {
// ...lots of various things, including:
sc: new SomeClass(new AnotherClass())
};
}
So the real app is built using buildApp, which gives SomeClass its AnotherClass instance. Your tests for SomeClass would use someClass_testSomething and such, which uses the real SomeClass but a mocked-up instance rather than a real AnotherClass containing just enough of it for the purposes of the test.
My dependency-injection-fu is weak, though, and I frankly don't see how buildApp scales to the real world, nor do I see what you're supposed to do if a method has to create an object to do its job, e.g.:
SomeClass.prototype.doSomething = function() {
// Here, I need an instance of AnotherClass; maybe I even need to
// create a variable number of them, depending on logic internal
// to the method.
};
You're not going to pass everything the method needs as arguments, it would be a spaghetti nightmare. This is probably why for more static languages, there are usually tools rather than just coding patterns involved.
In JavaScript, of course, we have another option: Just go ahead and use new AnotherClass in the code:
anotherclass.js:
function AnotherClass() {
}
AnotherClass.prototype.foo = function() { /* ... */ };
AnotherClass.prototype.bar = function() { /* ... */ };
AnotherClass.prototype.baz = function() { /* ... */ };
someclass.js:
function SomeClass() {
// ...app logic...
// Use AnotherClass instance `a`; let's say you're going to call `foo`,
// but have no use for `bar` or `baz`
(new AnotherClass()).foo();
// ...app logic...
}
someclass-test.js:
var AnotherClass;
function someClass_testSomething() {
// Just enough AnotherClass for this specific test; there might be others
// for other tests
AnotherClass = function() {
};
AnotherClass.prototype.foo = function() { /* ...appropriate `foo` code for this test... */};
var sc = new SomeClass();
// ...test `sc`...
}
function someClass_testSomethingElse() {
// ...
}
You use anotherclass.js and someclass.js in your real app, and you use someclass.js and someclass-test.js when testing SomeClass.
That's a rough sketch, of course; I'm assuming your real-world app probably doesn't have globals (SomeClass, AnotherClass) all over the place, but however it is you're containing SomeClass and AnotherClass can presumably also be used to contain SomeClass, and to contain the tests for it and their various fake AnotherClasss.
Related
How does Angular resolve all it's variables regardless of where there placed in a component?
For example in Vanilla JS
console.log(a) // undefined
let a = 'Hello;
Angular component
ngOnInit(){
this.example()
}
example(){
console.log(this.a) // Hello
}
a = 'Hello'
I'm aware that this is bad practice and the compiler will complain about that placement of the variable but none the less I am curious how Angular achieves this, or whether it's not an Angular specific behaviour?
This is not an Angular behavior. Actually the piece of code that you provided is inside a class, and the a is not a variable, actually it's a property.
JavaScript (and Typescript) doesn't requires properties to be declared before methods (neither constructor), since it's just a declaration that will be used futurely when this class will be instantiated.
Although tslint may warn you about the placement of it after methods, it's just a coding style concern.
You may translate a class to a traditional function constructor:
class Car {
make = 'default';
drive() {
/* ... */
}
model = 'foo'
}
can be wrote as (and is converted to when using some polyfill on browsers that doesn't support ES6 Class):
var Car = function() {
this.make = 'default';
this.model = 'foo';
}
Car.prototype.drive = function() {
/* ... */
}
Note that in the second case, the properties are defined inside the constructor, so it will always run before the method be called.
Situation: using functions to declare your Classes
If you are using and declaring classes with some custom (or framework function) as WinJs does (check their open source git directory), you are certainly familiar with this kind of code:
function define(constructor, instanceMembers, staticMembers) { }
function derive(baseClass, constructor, instanceMembers, staticMembers) { }
define(function constructor(){
this.yourProperty = 1;
}, {
// Prototype object
somePrototypeFunction: function(){
// When you type "this." here, it will not show up "yourProperty" declared
// in the constructor, because you have not instanciated the class,
// intellisense does not know that everything is linked
}
}
Common problem on these "custom" functions
Intellisense does not show up the values declared within the constructor when you try to reach them from the prototype functions.
I found something that have helped me: http://social.msdn.microsoft.com/forums/windowsapps/en-US/3eee400a-fefd-4f5e-9109-68df03fef006/javascript-intellisense-with-this-inside-gettersetter
This leaded me to the solution that I share to you below, it was a pain to make it work, and actually I was about to ** AGAIN ** let go with that problem which was something really disapointing especially with big team projects.
I find it weird that there are not many complaints about this on the web, maybe it's a configuration problem? However I had that problem on all VSD installations I saw.
So I hope the following solution will help you too if you run into the same situation.
After a few hours I finally have a solution which is not perfect (I have handled .base like in C# in my javascript library, but with the following code I can't say to intellisense that this ".base(...) " exists in the context of the prototype functions and constructor). If you have any tip on how to do that let me know, I'm interested.
Tested on Visual Studio 2013.
Simply change window.define / window.derive to the namespace and name you actually use (for WinJs it would be WinJS.Class.define and WinJS.Class.derive).
Add in _references.js the relative path of the file where you will put the following code, just after your library
And that's all! You'll have intellisense inside your
(function (window) {
"use strict";
/*
* Goal: make intellisense understand that the constructor of your define/derive functions are linked to the prototype object you have supplied.
* Tested on WinJs library and other custom libraries.
* Save this in a file, and reference it only in _references.js, insert it after your library containing the define/derive functions
*/
function initIntellisenseFor(constructor, baseClass) {
var inst = new constructor();
// Force intellisense to run function
for (var key in inst) {
if (typeof inst[key] == 'function') {
try {
inst[key]();
} catch (e) {
// Silent fail if wrong arguments (not sure if needed)
}
}
}
// Force intellisense to discover constructor
inst.constructor = constructor;
// Missing: .base() implementation for each method with redirection to the appropriate parent class method
}
var oldDefine = window.define;
window.define = function (constructor, instanceMembers, staticMembers) {
var result = oldDefine.call(this, constructor, instanceMembers, staticMembers);
initIntellisenseFor(result);
return result;
};
var oldDerive = window.derive;
window.derive = function (baseClass, constructor, instanceMembers, staticMembers) {
var result = oldDerive.call(this, baseClass, constructor, instanceMembers, staticMembers);
initIntellisenseFor(result, baseClass);
return result;
};
})(this);
I have module pattern done like this:
var A = (function(x) {
var methodA = function() { ... }
var methodB = function() { ... }
var methodC = function() { ... }
...
...
return {
methA: methodA,
methB: methodB
}
})(window)
This code let's me call only methA and methB() on A which is what I want and what I like. Now the problem I have - I want to unit test it with no pain ot at least with minimal efforts.
First I though I can simply return this but I was wrong. It returns window object.(can someone explain why?).
Second - I found solution somewhere online - to include this method inside my return block:
__exec: function() {
var re = /(\(\))$/,
args = [].slice.call(arguments),
name = args.shift(),
is_method = re.test(name),
name = name.replace(re, ''),
target = eval(name);
return is_method ? target.apply(this, args) : target;
}
This method let's me call the methods like this: A.__exec('methA', arguments);
It is almost what I want, but quite ugly. I would prefer A.test.methA() where test would never be used in production code - just for revealing private methods.
EDIT
I see people telling me to test the big thing instead of the small parts. Let me explain. In my opinion API should reveal only the needed methods not a bunch of internal functions. The internals because of their small size and limited functionality are much easier to test then test the whole thing and guess which part gone wrong.
While I may be wrong, I would still like to see how I could return references to all the methods from the object itself :).
Answer to your first question(you return this, but it returns window, not the object you wanted): in javascript this inside the function returns global object unless this function is a method of the object.
Consider next examples:
1) this points to the global object ():
function(){
return this;
}
2) this points to the object:
var obj = {
value: "foo",
getThisObject: function(){
return this;
}
}
Your case is example #1, because you have a function, that returns an object. This function is not a method of any object.
The best answer to your second question is to test only public methods, but if
that is so important for you, I can propose next:
create your modules dynamically on server side.
How it works:
create separate scripts for functionality you want;
create tests for these separate scripts;
create method that will combine scripts into one however you want;
to load script, reference to the combining scripts method.
Hopefully, it can solve your problem. Good luck!
Why not use namespaces to add your modules and public methods to js engine. Like this:
window['MyApp']['MODULE1'] = { "METHOD1" : {}, "METHOD2" : {}};
I write modules like this Sample module in JavaScript.
And test it like this: Simple unit testing in JavaScript
The use of eval() is generally not good idea.
Disclaimer: I am using ExtJS 3, but I don't think it's very relevant to the question, outside of the common use of it's namespacing function.
I have a singleton that's declared in a really long namespace like this:
Ext.ns("REALLY.REALLY.LONG.NAMESPACE");
var Singleton = (function() {
var foo = {
bar: "baz"
};
var privateFunction = function(param){
// ...
return foo;
};
var single = Ext.extend(Object, {
constructor: function(config) {
Ext.apply(this, config);
},
otherFunction: privateFunction,
publicFunction: function (someObject){
// do stuff with someObject
}
});
return single;
})();
// Make it a singleton
REALLY.REALLY.LONG.NAMESPACE.Singleton = new Singleton();
I use it in other modules via calls like REALLY.REALLY.LONG.NAMESPACE.Singleton.otherFunction(); and REALLY.REALLY.LONG.NAMESPACE.Singleton.publicFunction(myObject); . I'm wondering if I can swap out those calls by setting up the client module with an alias to the singleton, i.e. var singleton = REALLY.REALLY.LONG.NAMESPACE.Singleton; , so that I can call singleton.otherFunction();. I'm wondering if this is an anti-pattern , or if there are any pitfalls (memory?) I might run into through this usage.
Thanks StackOverflow!
I'm wondering if I can swap out those calls by setting up the client module with an alias to the singleton
Yes, you can.
I'm wondering if this is an anti-pattern , or if there are any pitfalls (memory?) I might run into through this usage.
No, there aren't any that I can think of and it is faster than calling the fully-qualified version.
Local Alias Pattern
Example:
function somefunc(){
var singleton = REALLY.REALLY.LONG.NAMESPACE.Singleton;
singleton.publicFunction();
};
Or:
(function somfunc(singleton){
}(REALLY.REALLY.LONG.NAMESPACE.Singleton));
Test Results:
http://jsfiddle.net/jMg9A/
There is no issue with creating a reference to the original "object". In many cases we create a namespace to organize our code, but of course, this can lead to really long namespaces that we really don't wish to reference later, thus creating a local reference to that namespace is an excellent idea so that you can change it in one place instead of various places.
I don't really see an ant-pattern here, instead I see an opportunity to make it simpler for yourself and probably a little more manageable from a developer standpoint.
I'm using a design pattern that uses the return statement to expose public class methods.
Problem is: I'm getting a lot of JSC_INEXISTENT_PROPERTY warnings in Closure Compiler's Advanced mode, which makes it difficult to check the warnings that actually matter.
Example of the pattern I use:
// ==ClosureCompiler==
// #compilation_level ADVANCED_OPTIMIZATIONS
// ==/ClosureCompiler==
/**
* #constructor
*/
var MyClass = function() {
var someFunc = function(myString) {
console.log(myString);
}
return {
myPublicFunc: someFunc
};
}
var myClassInstance = new MyClass();
myClassInstance.myPublicFunc('Hello World');
Warnings:
JSC_INEXISTENT_PROPERTY: Property myPublicFunc never defined on MyClass \
at line 16 character 0
myClassInstance.myPublicFunc('Hello World');
Output (formatted):
(new function() {
return {
a: function(a) {
console.log(a)
}
}
}).a("Hello World");
Which is weird, because Closure understood what the code was doing and compiled the code correctly, renaming myPublicFunc consistently to a. So why did I get this warning? Am I doing something wrong?
Note: I do not want to turn off these warnings because it would also hide warnings I actually care about. I also do not want to use quoted strings or exports because I do want Closure to compress these.
Your function is annotated incorrectly. It's actually not a constructor and in this case the new keyword is unnecessary. Your function simply returns an anonymous type with a myPublicFunc property.
To annotate such a pattern, you would use the record type:
/** #return {{myPublicFunc: function(string) }} */
var MyClass = function() {
var someFunc = function(myString) {
console.log(myString);
}
return {
myPublicFunc: someFunc
};
};
var myClassInstance = MyClass(); // new keyword not needed
myClassInstance.myPublicFunc('Hello World');
Another annotation option is to create an interface and type-cast the returned object to be that interface. This option would be useful when multiple functions return an object that conforms to the same interface.
You can also use:
/** #type {function(new:{myPublicFunc: function(string)} )} */
var MyClass = function() {...
The function can be called with "new" but doesn't return an instance of "MyClass".
Adding
MyClass.prototype.myPublicFunc = null;
would solve the problem though I don't know whether this is the best solution.
I don't really know how the compiler works, but I could imagine that if you have a constructor function, it expects instance properties to be assigned to this inside the constructor or to MyClass.prototype.
If you remove the #constructor annotation and omit new, then there is not warning (but the compiled code is only console.log("Hello World");.