Re: Database testing and EOF; junit testrunner environment;
Re: Database testing and EOF; junit testrunner environment;
- Subject: Re: Database testing and EOF; junit testrunner environment;
- From: Christian Pekeler <email@hidden>
- Date: Fri, 7 Jul 2006 19:16:12 -0600
I'd be interested to hear how you approach testing EOs. I can
understand the motivation to exclude the database so that the test
run quickly and hence can be run frequently. However, I usually
find that very few of the interesting methods of my EOs can be
tested without a network of other EO objects.
Some examples:
MyEO has has a dozen relationships to other EOs, many of which are
mandatory in the model. I want to test a method foo() that only
interacts with two of those relationships. So all I'm doing:
public void testFoo() {
MyEO myEO = (MyEO)mockEditingContext().createSavedObject
(_MyEO.ENTITY_NAME);
myEO.addToAsRelationship(mockEditingContext().createSavedObject
(_A.ENTITY_NAME));
myEO.addToAsRelationship(mockEditingContext().createSavedObject
(_A.ENTITY_NAME));
B b = (B)mockEditingContext().createSavedObject(_B.ENTITY_NAME);
b.setSomethingNecessaryForFoo(...);
myEO.setBRelationship(b);
myEO.foo();
assert...
}
I.e. I don't concern myself with setting up the whole object graph.
All I'm doing is setting up the absolute minimum for testing foo().
Now let's say foo()'s implementation calls bar(), which traverses a
huge portion of the object graph and then returns a number. Still,
all I want to test is foo(). So what I usually do is taking control
of bar() by creating an inner class inside the test case that
inherits from MyEO and overwrites bar():
class TestMyEO extends MyEO {
int bar;
protected int bar() {
return bar;
}
}
public void testFoo() {
TestMyEO myEO = new TestMyEO();
mockEditingContext().insertSavedObject(myEO);
myEO.bar = 0;
...
// assert that foo does the right thing if bar returns 0
myEO.bar = 30;
// assert that foo does the right thing if bar returns 30
...
}
Now we still want to test bar() itself, and let's assume that the
test would only be meaningful if lots of objects are involved, so
then lets make it easy to setup those objects to keep the test method
as short as possible:
void addNewCToMyEO(MyEO myEO, String name, int age) {
C c = (C)mockEditingContext().createSavedObject(_C.ENTITY_NAME);
c.setName(name);
c.setAge(age);
myEO.addToCsRelationship(c);
}
public void testBar() {
MyEO myEO = (MyEO)mockEditingContext().createSavedObject
(_MyEO.ENTITY_NAME);
addNewCToMyEO(myEO, "abc", 3);
addNewCToMyEO(myEO, "def", 20);
addNewCToMyEO(myEO, "ghi", 9);
addNewCToMyEO(myEO, "abc", 1);
addNewCToMyEO(myEO, "def", 2);
addNewCToMyEO(myEO, "ghi", 5);
assertEquals(40, myEO.bar());
}
I find that with techniques like these I can test all of the test-
worthy stuff in my business logic. Sometimes it's getting more
complicated and I need to subclass several EOs and create objects of
many EOs to setup a unit test. This is often a symptom for badly
designed code (I'm just speaking about my own). The more experienced
I get at TDD, though, the simpler and easier my test cases get.
Some times it is reasonable to create these by hand, but often
this can be hundreds or thousands of objects.
Do you really need all those objects to unit test individual methods?
If none of my examples would help, maybe you could explain one of
your complex scenarios and we'll take a crack at making it testable
without a DB.
So, although it makes the tests slow, I find it easier to read
them from a known state in the database. Do you have two sets of
tests, one quick, programmatic only set and one functional,
database using, slow set?
I have unit tests that test units of code as much isolated as
possible (i.e. with the fewest number of other objects involved), and
without accessing the database. And then I'm working with a QA team
that creates acceptance tests against a controlled database and also
does exploratory testing against a production-data like database.
Christian
Attachment:
smime.p7s
Description: S/MIME cryptographic signature
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Webobjects-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden