Maybe we don't need Configuration Factories after all

6 views
Skip to first unread message

Cédric Beust ♔

unread,
Jun 15, 2006, 4:20:52 PM6/15/06
to testn...@googlegroups.com
I believe we can already achieve an effect similar to Configuration Factories using the existing @Factory.

Consider:

public class A {
  @Factory
  public Object[] createConfigurations() {
    return new Object[] { new B() };
  }
 

And then we put our @Configuration methods on B.  Here is what happens:
  • B.beforeSuite and B.beforeTest do get called before test methods on A.
  • However, B.beforeTestClass and B.beforeTestMethod don't, because these configuration methods should only work on the same class as the test method.
In short, the only limitation with the current implementation is that beforeTestClass and beforeTestMethod methods have to be on the same class (or a parent), but all other @Configuration methods can be put anywhere.

It seems to be a reasonable limitation to me, so we could do away with the @ConfigurationFactory idea and stay with @Factory (soon to become public interface ITestFactory).

Thoughts?

--
Cédric

Alexandru Popescu

unread,
Jun 19, 2006, 1:07:24 PM6/19/06
to testn...@googlegroups.com
Hi!

I haven't got time to get to this one. I will play with it tomorrow
and see if it covers what I have in mind.

./alex
--
.w( the_mindstorm )p.

Alexandru Popescu

unread,
Jun 19, 2006, 2:42:48 PM6/19/06
to testn...@googlegroups.com
I've been thinking about this more and I think that this is not really
a replacement for my proposal. And here is why:

1/ IIRC you can have Before/After Suite/Test methods defined in a
class and simply invoked by providing them in the suite definition
file. The @Factory part would be just a syntactic sugar.

2/ the real problem with this approach is that your test is not having
access to the ConfigurationMixin instance, so that it can use
resources from there. Imagine the classical scenario with DB
interaction. You start/stop the embedded db in the Before/AfterSuite
but you have no means to get the hands on a connection without either
statically referencing the suite @Configuration class or by having it
in your test hierarchy.

./alex
--
.w( the_mindstorm )p.


On 6/15/06, Cédric Beust ♔ <cbe...@google.com> wrote:

Cédric Beust ♔

unread,
Jun 19, 2006, 3:08:14 PM6/19/06
to testn...@googlegroups.com
On 6/19/06, Alexandru Popescu <the.mindstor...@gmail.com> wrote:
I've been thinking about this more and I think that this is not really
a replacement for my proposal. And here is why:

1/ IIRC you can have Before/After Suite/Test methods defined in a
class and simply invoked by providing them in the suite definition
file. The @Factory part would be just a syntactic sugar.

True.

2/ the real problem with this approach is that your test is not having
access to the ConfigurationMixin instance, so that it can use
resources from there.

Why not?

The factory creates instances of objects, which can expose getters and setters.  And conversely, these factories can be created having knowledge on the tests that are about to be run.

--
Cédric

Alexandru Popescu

unread,
Jun 19, 2006, 3:21:00 PM6/19/06
to testn...@googlegroups.com

But how do you access these from your test? Say I have DbConfiguration
and MyTest classes. How can I access DbConfiguration instance from
MyTest?

./alex
--
.w( the_mindstorm )p.

> --
>
> Cédric
>
> >
>

Jesse Kuhnert

unread,
Jun 19, 2006, 4:11:15 PM6/19/06
to testn...@googlegroups.com
Maybe Hani is right in that this starts to feel like a sort of pseudo dependency injection, but I have more examples to illustrate .

Has anyone used the more recent versions of http://easymock.org/   ? They've added static imports of the mock functions now, so you get to do cool stuff like:

public void testSomething()
{
   MyInterface foo=createMock(MyInterface.class);

   replay(foo);
   
   foo.doSomeStuff("myval");

  veryify(foo);
}

But already this is still less ideal from a "testing infrastructure" sort of viewpoint. I've seen test base classes for easymock where replay() / verify() are methods implemented on the base class that iterate over the known list of all created mock objects so that you don't have to pass them into replay/verify (they are vararg methods) in your tests..

Static imports go a loooongg way towards making things a lot easier, but they aren't a very good place to store state. You could end up creating a whole new set of classes / functionality just to maintain the state of these static imports if you were trying to manage DB connections / mock objects etc....Not a pretty scenerio imho . (though it is of course do-able ) .

That's why I liked the idea. It allows you to create really simple configuration classes for some of these things that can then be "merged"/whatever you want to call it with the test class in question, ultimately leaving ~everything~ simple/maintainable without having to manage inheritance hierarchies for different types of tests.

my 2 cents...
--
Jesse Kuhnert
Tacos/Tapestry, team member/developer

Open source based consulting work centered around dojo/tapestry/tacos/hivemind.

Cédric Beust ♔

unread,
Jun 19, 2006, 7:27:31 PM6/19/06
to testn...@googlegroups.com
Not sure I understand, can you give me a concrete example of your @ConfigurationFactory?  And then I'll try to convince you that I can achieve the same result with the existing @Factory :-)

--
Cedric
--
Cédric

Jesse Kuhnert

unread,
Jun 19, 2006, 10:04:52 PM6/19/06
to testn...@googlegroups.com
Damn...I was thinking about this point as well while I was away. Too bad you noticed :)

If you would humor me, I will go back to my easymock example. There are three core static method imports that you can now use:

createMock(Class clazz);
verify(Object... mocks);
replay(Object... mocks);

The "problem" is that in the current static import form with easymock and no base class to descend from you would have to do something like this:

public void testFoo(){
  InterfaceA inta = createMock(InterfaceA.class);
  InterfaceB intb = createMock(InterfaceB.class);
 
  inta.add(intb);
  expect(inta.wiggle("foobar")).andReturn(true);
  
  replay(inta, intb);

  inta.doYourStuff(intb); // all things done before replay
  // are now expected to happen
 
  verify(inta, intb);
}

This may be alright in a trivial example, but in more complicated scenerios it can start to become a real pain in the ass to have to remember to pass in all the interface mocks that you've created. A base class has served this purpose previously, such that this call:

...
InterfaceA inta = createMock(InterfaceA.class);
...

Would actually be implemented by an inherited method that would create the mock AND store a reference to it in some local list. Then, when the subsequent call to verify() is invoked:

... verify()

It won't matter how many mocks you've called, the base class will know this transitory information and pass the right arguments in for you. Keeping your tests mostly nice and clean.

So....there are the existing problems and solutions via inheritance. I was ~hoping~ that whatever mix-in magic exists might be able to let us define a basic configuration class that only handles verify/replay for us, keeping track of the mock objects created..As in the example.

The whole idea sounds great until the issue of trying to code to an interface that doesn't exist until it's been mixed in comes up. That, I must confess seems to blow up that whole theory. Why can't we just say "define verify()" ? =p

Alex, perhaps your black magic will come in to save me now or is this just not something that is possible? Maybe there is another approach that will handle it better. I could certainly always "delegate" to a configuration factory object I suppose....

I just liked the idea. Haven't personally played with this in java. Ok I feel like an ass now a little bit. :/

Alexandru Popescu

unread,
Jun 20, 2006, 4:22:37 AM6/20/06
to testn...@googlegroups.com
#: Cédric Beust ♔ changed the world a bit at a time by saying (astral date: 6/20/2006 2:27 AM) :#

> Not sure I understand, can you give me a concrete example of your
> @ConfigurationFactory? And then I'll try to convince you that I can achieve
> the same result with the existing @Factory :-)
>

Here is a small/draft example:

[code]
public class MyTest {
private DbConnectionFactory m_connectionFactory;

@ConfigurationFactory
public DbConnectionFactory initializeDataSource() {
m_connectionFactory= new DbConnectionFactory();
return m_connectionFactory;
}

@Test
public void sqlInsert() throws SqlException {
Connection conn= m_connectionFactory.getConnection();
// do the rest
}
}

public class DbConnectionFactory {
private Connection m_connection;

@BeforeClass
public void initializeConnection() {
m_connection = MySpringContext.getBean("dataSource").getConnection();
}

@AfterClass
public void closeConnection() throws SQLException {
m_connection.close;
}

public Connection getConnection() {
return m_connection;
}
}
[/code]

hope this clarifies my intention,

./alex
--
.w( the_mindstorm )p.

ps: Jesse I will try to re-read your message and see if I can put it in a better shape to impress
Cedric :-).


Alexandru Popescu

unread,
Jun 21, 2006, 9:46:13 AM6/21/06
to testn...@googlegroups.com
Ced, any thoughts about this?

./alex
--
.w( the_mindstorm )p.

Reply all
Reply to author
Forward
0 new messages