So I’ve started my new job and I’m working with Flex and ActionScript 3. I was tasked with throwing together a couple classes and there respective unit tests this week. The classes don’t integrate with any external resources and mostly do pass through except for some cross cutting concerns (e.g. – logging, security, etc). I figured writing my tests would be pretty straight forward: throw together the appropriate test cases and in each mock out any dependencies.
Now when I think about a language I try to put it into the context of other languages I’ve had experience with, identify differences in language elements, and work from there. With respect to ActionScript, I tended to problem solve in the context of JavaScript since they are both based on ECMAScript, but I’ve run into some frustrations along the way.
To mock out an object in a test using JavaScript I’d typically write something like:
1
2
3
4
5
| var dependency = new MyDependency();
dependency.methodToMock = function () { return true; };
var obj = new MyClass(dependency);
assertTrue(obj.passThroughMethodUsingMockThatICreated()); |
or if I wanted to mock out objects being instantiated by a dependency that I couldn’t inject:
1
2
3
4
| MyDependency.prototype.methodToMock = function () { return true; };
var obj = new MyClass();
assertTrue(obj.passThroughMethodUsingMockThatIDidntCreate()); |
In ActionScript, assuming that MyDependecy is declared in an ActionScript class, the first and second approach I used in the above will not work. I did some reading on the Flex 3 livedocs and found out that the culprit was the traits object that was introduced in AS3. To abridge, the traits object is a copy of all applicable properties from parent classes and defined properties in the current class that need to be available at run-time to help reduce the performance hit of walking the prototype chain previously used for inheritance. The traits object is an internal mechanism which is not accessible by the developer. Prototype-base inheritance is still available, but falls secondary to traits. Awesome.
So unless I declare the methods of my class as members of the prototype for the class, I can’t manipulate them at run-time. So instead of the following:
1
2
3
4
5
| public class MyDependency {
public function methodToMock() : Boolean {
...
}
} |
I’d have to write:
1
2
3
4
5
| public class MyDependency {
prototype.methodToMock = function() : Boolean {
...
}
} |
So now I’ve got methodToMock available in a data structure I can mess with at run-time. I still, however, can’t accomplish what I did in JavaScript unless I add the keyword dynamic to the class declaration (as below) or remove the “strict” flag from the compiler:
1
2
3
4
5
| public dynamic class MyDependency {
prototype.methodToMock = function() : Boolean {
...
}
} |
Now I can manipulate the object and its class’ prototype the way I would in JavaScript. It irks me a bit that performance was the driving force for all of this hoopla, but I’m just an application developer, so I won’t pretend to understand all of the motivations for these decisions.
As another alternative, I thought about just using Object for all of my mocks, but I quickly dismissed the option since we’re using the explicit typing with ActionScript, as I suspect most are since its promoted for its performance boost. I also looked into using the Proxy class as a run-time solution, but alas it can’t be instantiated, only extended; this would mean writing class declarations for every mock I wanted to create, which seems kinda silly, and I still would have to deal with the explicit typing issue. On a side note, it would have been nice if Proxy had the option to be instantiated with the object it’s proxying as a constructor argument, mimic the type passed as the argument, and allow run-time manipulation. No idea if this is feasible though, so I’ll count it as a pipe dream for now. In any case, from my experience mocks are intended to be used within a context and disposable for the purpose of testing; why would I write anything more than inline code to utilize mock objects?
In the end, I’m probably going to be making end-to-end tests using stubs for the classes I want to test. Once we have some time to evaluate mock object libraries for ActionScript, I’ll probably start digging again for more answers. We’ll eventually need something to help us with expectation-based testing anyway, so a library will be the way to go. Hopefully I’ll end up finding something more like Mocha or Moq than JMock, although I think the opposite may be true.
There are language elements in ActionScript that I’m extremely grateful to have at my disposal (e.g. – events, properties, functions, etc). A few quirks exist though (e.g. – object/class manipulation at runtime and reflection) that still get me when I try to think about ActionScript in the context of JavaScript. Going forward I think I’m going to switch gears and solve problems more as I would a Java/C# developer than a JavaScript developer, favoring the use of libraries over the language features to get every day tasks done. I like ActionScript, but what good would a blog be if I couldn’t complain.
NOTE: I can’t take credit for the tagline, some Flex developers I know have begun to adopt it and I borrowed it from Dan.