Summary
There are an incredible number of programming languages out there. What would it be like if we had a few with features that really supported testing?
Advertisement
I just noticed that Brian Marick had an interesting response to something I said in my last blog entry. I was talking about how difficult it is to instantiate classes outside of their applications. He mentioned that it would be great to have a tool that would allow you to create an arbitrary object and poke at it, test it etc, regardless of how many dependencies it has. You could supply the tool with mocks for the bad dependencies and it would use the mocks. That would be useful.
Brian's post reminded me of something I ended up making a while ago, a little framework I called Ghostworld. It was a tool for that sort of thing. I ditched it because I discovered that PicoContainer has every feature I added and quite a few more. The world doesn't need any more duplicate projects so Ghostworld remains unreleased. But, there is another reason why I never released Ghostworld. I felt it was incomplete. It was missing the killer feature. Let me tell you about it.
To make an arbitrary class you fill up the Ghostworld with types:
Ghostworld world = new Ghostworld();
world.addImposter("Profile", UserProfile.class);
...
Then you ask it to create an object:
Reservation res = (Reservation)world.makeObject("Reservation");
The ghostworld walks the constructors of Reservation and attempts to create one using the classes it knows about. So far, so good. PicoContainer does this also, but what I really wanted was a framework that lets me do this:
class Reservation
{
private AIGConnection connection;
public Reservation(..) {
connection = new AIGConnection(..);
}
}
world.addImposter("AIGConnection", TestingAIGConnection.class);
Reservation res = (Reservation)world.makeObject("Reservation");
Now, here's what I want to have happen. Every time that that Reservation object or one of its subobjects creates a AIGConnection using a 'new' expression, I want a TestingAIGConnection object to be created instead. In the example above, we'd now have a reservation which holds onto an instance of TestingAIGConnection rather than AIGConnection. Wouldn't that be useful? We could instantiate and test nearly any piece of code without refactoring. I'm not convinced that is great thing. Abused it would just let code get uglier without bound. But, used well, it could really help people out of same jams.
Unfortunately, I never had time to really dig in and find out whether there is some sort of classloader, AOP, or bytecode manipulation magic that would allow me to substitute classes over and over again at runtime. But, the thing that I have been reflecting about is the fact that there seems to be a lot of energy behind efforts like this. And when that happens it usually means that language support is something to consider.
I forget whether it was Paul Graham or Richard Gabriel (or someone else entirely) who said something like this: "the algorithm for developing every "next" language is simple.. it has to be more dynamic than its predecessor and it has to look like C." So, let's imagine a language like that.
(By the way, just in case you haven't seen it before, there's actually a language with syntax close to this. It's called Groovy).
The Account class is simple enough, but let's suppose we want to test it, and let's make it a real bear. The TransactionLog class talks to a database behind the scenes. Every time you add an entry, it's sloooowww.
The way languages are today, if we want to get past this, we have to add a constructor
that accepts a log, or introduce a factory method and override it, or.. well there are
a bunch of solutions, but what if we had a language which let us to do this?
test Account
{
class TransactionLog
{
entries = new ArrayList();
addEntry(entry) {
entries.add(entry);
}
}
testDeposit {
a = new Account();
a.deposit(3);
assertEquals(3, a.getBalance());
assertEquals(1, a.log.entries.size());
}
}
The language would allow us to define classes inside a test class. The classes we define in tests supersede classes outside the test. So, whenever some object creates a transaction log in this test class, they get an instance of this simple replacement class that doesn't touch a database.
Another feature... the tests have access to all private data.
Could these features be abused? Yes. If you can test without breaking dependencies it's easier to create snarls of complicated code. On the other hand, it would be much easier to get out of them too.
What do you think? Isn't it about time languages had first-class support for testing?
> <p>I just noticed that <a > href="http://www.testing.com/cgi-bin/blog">Brian > Marick</a> had an interesting <a > href="http://www.testing.com/cgi-bin/blog/2004/04/05#feathe > rs-coupling">response</a> to something I said in my last > blog entry. I was talking about how difficult it is to > instantiate classes outside of their applications. He > mentioned that it would be great to have a tool that would > allow you to create an arbitrary object and poke at it, > test it etc, regardless of how many dependencies it has. > You could supply the tool with mocks for the bad > dependencies and it would use the mocks. That would be > useful.</p>
If you use Java, you can do this by simply declaring standard methods as private inside of your classes (as opposed to creating test classes using package private access as JUnit does). These are then, not visible to the world as part of the objects API. However, you can grant AllPermission in a test harnass, and it can use introspection to find these standard methods, and invoke them in a way similar to JUnit.
I prefer in class tests because that allows me easy access to changing the tests as I develop and keeps everything together for compilation checks as well as for review...
Have you looked at Aspect Oriented Programming and at Aspect-J in particular? It might let you do what you want, not only at the constructor level but for methods as well.
The language would allow us to define classes inside a test class. The classes we define in tests supersede classes outside the test. So, whenever some object creates a transaction log in this test class, they get an instance of this simple replacement class that doesn't touch a database.
If I understand you correctly, this is what is known as partial classes - that is, classes that can be extended or changed after they are defined.
The next version of C# is supposed to bring partial classes using a special keyword partial. I don't know if C# partial classes will allow for the redefinition of methods, or just for the extension of a class with more methods. (BTW: The primary use of partial classes in C# is for code generation)
Ruby's classes are partial by default, and allow for redefining methods as per your example. I see no reason why your transaction log example shouldn't work as if in Ruby.
> (By the way, just in case you haven't seen it before, there's actually a language with syntax close to this. It's called Groovy). As others already said before: There is already a language that supports this style with even less line noise ({,}). It's Ruby (http://www.ruby-lang.org). It has excellent support for unit testing, mock objects, and all you need for test-driven development. Additionally, it makes fun!!
Which, incidentally, is where Unit Testing (as in JUnit), and XP (as in eXtreme Programming), and practically every other "modern" development idea was invented.
Mock objects? Make a dumb proxy and change doesNotUnderstand to always answer success, or failure, or whatever. Inspect and debug any object at any time, without restarting the app in "debug mode".
I am laughing AT the struggling java developers, not WITH them.
My current project has created a new IoC container called StructureMap (http://sourceforge.net/projects/structuremap) somewhat like PicoContainer in C# that is on the way to doing exactly what you are describing using what we call "Mock Injection." Any type constructed by the container can be set to be replaced with an NMock mock instance whenever the type is requested from the container. We have found this technique in conjunction with constructor injection to be very effective in isolating classes for unit tests. Right now the functionality only supports mocking one class at a time, but we are working on something that can look at a requested class, create it with the appropriate dynamic mocks, and return both the new object and the DynamicProxy objects in one step to simplify the mechanics of setting up unit tests. An NUnit test using this technique looks like this:
using System; using StructureMap; using NMock;
[TestFixture] public class MyClassTester { private IMock _dependencyMock;
[SetUp] public void SetUp() { _dependencyMock = ObjectFactory.Mock(typeof(IDependency));
}
[Test] public void Test1() { _dependencyMock.Expect("SayHello", "Hello");
MyClass foo = new MyClass(); foo.DoSomething(); _dependencyMock.Verify();
} }
public class MyClass { public void DoSomething() { IDependency dependency = (IDependency)ObjectFactory.GetInstance(typeof(IDependency)); dependency.SayHello("Hello"); }
Or...Objective-C (Todd I guess you will describe this better than me, I have seen you in the Cocoa/WebObjects lists)
2 features available in Objective-C that will enable you to do what you describe are Object Posing and Categories (aka mixin inheritance).
Posing lets a class present itself to the runtime as another class. Instances of the parent class will never be created, instead instances of the poser will be created.
Categories allow you to override or add methods to an existing class, without having to create a subclass or access the source.
I guess we do not need NEW languages but old ones. Still I understand why these features are "disabled" in JAVA :-) AOP will do the trick in JAVA I guess.