Skip to content
Oct 29 2009 / alecmce

ASUnit – A Conventional Problem

There are several conventions involved in unit-testing. If you use FDT, this structure will be familiar to you. If not, you should get the picture anyway:

A standard structure for a unit-tested project in FDT

TestRunner does one thing: starts the unit-test framework by adding the AllTests TestSuite. That AllTests will then in-turn add all of the AllTests in the next level of packages (in this case, just the one AllTests in the alecmce package). This happens recursively through the entire package tree. Any tests that lie in the same package as an AllTests are added by that AllTests, so alecmce.topsecret.AllTests is responsible for adding alecmce.topsecret.ThisClassWillChangeYourLifeTest.

This convention works really well. More and more people are adopting unit-testing while developing their tools/frameworks. Their tests are published alongside their tools/frameworks, so that you can be confident that they work as anticipated, and so that you can use the tests as a form of documentation for the known working functionality of the tools/frameworks.

Suppose you want to import a tool/framework into your project. For example (as it was the reason that this problem arose), let’s suppose I want to add as3signals into my project. Since it has a suite of tests, in case I need to make changes to the library, I want to add those tests to the suite of tests that I run. I download the framework from github and add it to my lib folder, adding the src and test folders as source folders:

A file-system with as3signals added as a library

There’s a problem here. There are two classes in the default package called AllTests. First there’s mine, which is responsible for adding alecmce.AllTests, then there’s also as3signal’s which is responsible for adding org.AllTests.

There is no way to differentiate between them; they conflict:

Error: Can not resolve a multiname reference unambiguously. AllTests

The convention of creating a class called AllTests in each package is clean and simple in the one-library environment. If you import multiple projects then the convention breaks down. Of course, there are other ways of importing libraries into yours: you could package them up as swcs (or else, use the swc provided), or you could create separate projects in FDT and link the projects together (assuming you use FDT of course – though I’m sure other environments can work similarly).

For me, that diminishes the point of using unit-testing. I want to have all the code that goes into my project tested all the time. While I don’t expect to change signals, I want to be able to reassure myself that everything is still working as I anticipate it to for all the code, every time I run my tests.

A change in convention?

If instead of AllTests I called my tests TopsecretAllTests or AllTests_topsecret and the signals tests were called SignalsAllTests or AllTests_signals the class ambiguity would disappear. It is feasible however that two people could end up using the same project name under different packages. Then, maybe two people would end up with AllTests_topsecret classes and the ambiguity would persist.

The guaranteed solution is to append the full package name onto each AllTests class: AlllTests_alecmce_topsecret is a candidate. Then, two tests’ packages would only conflict if the packages themselves conflict (in which case the tests are the least of their problems). However, this seems like over-kill.

Unfortunately, because the AllTests convention is the convention, this problem is thorny. Even if the AllTests_topsecret pattern is an acceptable work-around, it will not be adopted by people until the need arises, and then, probably, any number of different practises will emerge. The existing norms are well known, well documented and in common practise. It is, effectively, a problem without a solution.

  • http://twitter.com/alecmce alecmce

    Thinking about this problem with #asunit has taken up most of my morning… but it does need thought: http://bit.ly/37yxFR
    This comment was originally posted on Twitter

  • http://asunit.org Luke Bayes

    Hey Alec,

    Great post!

    First off, I’d like to point at the compiler, and say that when it finds two identically-named classes, it should simply use the one that appears first in your class path. I’m pretty sure this is what Java does, and while it wouldn’t get you exactly what you want, it also wouldn’t just break.

    We’re using Sprouts (http://projectsprouts.org), and the latest test suite generator doesn’t throw suites all over the test path. It now just creates a single test suite at the root of the test package.

    We recently ran into a similar problem in that we wanted to run unit tests against multiple test packages, and the solution wound up customizing the Sprout generators so that they could run with multiple path inputs. This worked locally, but hasn’t yet been integrated with trunk.

    What I was hoping to do, was basically change the main generator so that it would search in all paths added to the MXMLC source-path, for *Test.as, but then only add the single Test Suite to your ‘test’ package.

    This may only work for your case if you can also delete their outer test suite from your version control.

  • http://twitter.com/retrogamer4ever retrogamer4ever

    ASUnit – A Conventional Problem http://bit.ly/aiyJl
    This comment was originally posted on Twitter

  • http://alecmce.com Anonymous

    Thanks Luke,

    I was thinking about something broadly similar using AIR to inspect the directories and automatically generate the suite of tests, but perhaps Sprouts offers a more interesting solution.

    As ever though, thinking about and working on tooling , or learning new working practices takes me away from the job-at-hand… when I have time I will try to get to grips with Sprouts.

    Then you’ll probably need to start fielding blog posts about that too! ;-)

  • http://alecmce.com alec

    Thanks Luke,

    I was thinking about something broadly similar using AIR to inspect the directories and automatically generate the suite of tests, but perhaps Sprouts offers a more interesting solution.

    As ever though, thinking about and working on tooling , or learning new working practices takes me away from the job-at-hand… when I have time I will try to get to grips with Sprouts.

    Then you’ll probably need to start fielding blog posts about that too! ;-)

  • http://asunit.org/ Luke Bayes

    Actually, I’ve been waiting for AIR to support interacting with external applications (AIR 2.0!), and with that I’m hoping to get a GUI in front of Sprouts in the not-too-distant future…

    I think Robert Penner might be considering porting the XUL UI to AIR as we speak. Check in with him before you start, as that could be a great collaboration!

    As far as fielding your posts about Sprouts, I’m definitely looking forward to it!

  • http://asunit.org Luke Bayes

    Actually, I’ve been waiting for AIR to support interacting with external applications (AIR 2.0!), and with that I’m hoping to get a GUI in front of Sprouts in the not-too-distant future…

    I think Robert Penner might be considering porting the XUL UI to AIR as we speak. Check in with him before you start, as that could be a great collaboration!

    As far as fielding your posts about Sprouts, I’m definitely looking forward to it!

  • http://www.article-elf.com/ forex robot

    Great post this will really help me.

  • http://asunit.org/ Luke Bayes

    Hey Alec,

    Great post!

    First off, I'd like to point at the compiler, and say that when it finds two identically-named classes, it should simply use the one that appears first in your class path. I'm pretty sure this is what Java does, and while it wouldn't get you exactly what you want, it also wouldn't just break.

    We're using Sprouts (http://projectsprouts.org), and the latest test suite generator doesn't throw suites all over the test path. It now just creates a single test suite at the root of the test package.

    We recently ran into a similar problem in that we wanted to run unit tests against multiple test packages, and the solution wound up customizing the Sprout generators so that they could run with multiple path inputs. This worked locally, but hasn't yet been integrated with trunk.

    What I was hoping to do, was basically change the main generator so that it would search in all paths added to the MXMLC source-path, for *Test.as, but then only add the single Test Suite to your 'test' package.

    This may only work for your case if you can also delete their outer test suite from your version control.