But this is a simple PoC, and so I tried to mitigate effort as much as
possible.
So I tried setting up a super class for the test classes themselves
where the super class would build the SessionFactory based on override-
able methods (usually the only thing that varies between tests is the
mapping files used). This super class would build the SessionFactory
in a method annotated with @BeforeClass and close it in a method
annotated with @AfterClass.
What I seemed to find, though, was that TestNG did not recognize when
annotations occurred on superclass. Is that by design? Or a bug? Or
am I just doing something wrong?
If I'm reading it correctly this should definitely work. Can you
reduce it to some reproductible test case?
./alex
--
.w( the_mindstorm )p.
TestNG co-founder
EclipseTestNG Creator
>
> >
>
So something like:
@BeforeClass
private void doSomeSetUp() { ... }
will not work.
Any plans to work this on private members?
Do you see any valid reasons for doing this? I think this may lead to
interpretable behavior when used in inheritance contexts.
Sorry, I don't understand what you mean by "interpretable behavior".
[code]
class Parent {
protected SessionFactory m_sessionFactory;
@BeforeClass
private initSessionFactory() {
m_sessionFactory = ...
}
}
class Child {
@Test
public debatable() {
assert m_sessionFactory == null // my expectation as
initSessionFactory is not accessible from Child instance
assert m_sessionFactory != null // Steve's expecation
}
}
[/code]
bests,
[code]
class Parent {
private SessionFactory sessionFactory;
@BeforeClass
private initSessionFactory() {
sessionFactory = ...;
}
protected SessionFactory getSessionFactory() {
return sessionFactory;
}
}
class Child extends Parent {
@Test
public void sorryButThisIsNotReallyDebatableToMe() {
// To me, it is *totally* reasonable to expect that
getSessionFactory() returns non-null here...
assert getSessionFactory() != null;
}
}
[/code]
[code]
@Test
class SomeTest implements IHookable {
/** A real test. Gets picked up correctly, no problem... */
public void testIt() { ... }
/**
* Impl of IHookable#run. As impl of interface, this needs to be
public scope
* and thus TestNG tries to run this as a test here, and of course
fails because
* of the parameters...
*/
public void run(IHookCallBack callback, ITestResult result) {
callback.runTestMethod( result );
}
}
[/code]
You see, we already have a debate :-). I don't see any reasons for
which a parent private method should be visible to its children (or at
least no valid reasons so far).
I think we can do better in this case and filter out that method.
getSessionFactory() is in fact protected for the explicit purpose of
exposing to "children" (aka subclasses).
Therefore I have to assume you mean the initSessionFactory() method.
In which case, you and I have very different definitions of
"visible". The Child class cannot "see" it, cannot call it. I
suppose you might mean in terms of the execution? Um, how is
@BeforeClass any different than other initialization code (like say a
constructor) that could in fact run when the subclass in
instantiated? And besides, in this argument, how is making it
protected now "good"? All that does is expose internal workings of
the superclass which the subclass can now call and possibly screw
things up. From a theoretical PoV, your thinking here is completely
incorrect IMHO. Not picking up that initSessionFactory() call breaks
the superclass/subclass contract. Sorry, I still don't see a debate
here; I think my view is unequivocally correct ;)
Anyway, like I said I don't really care: its a test-suite. I can
largely control how people (read me and the rest of the hibernate dev
team) access these classes. This is now a theoretical discussion to
me. The practicality is that making it protected makes it "work".
@BeforeClass really could be achieved via constructor (of course I'd
still have problems with the other "scaffolding" annotations like
@AfterClass or @BeforeMethod):
[code]
class Parent {
private SessionFactory sessionFactory;
protected Parent() {
initSessionFactory();
}
private initSessionFactory() {
sessionFactory = ...;
}
protected SessionFactory getSessionFactory() {
return sessionFactory;
}
}
class Child extends Parent {
@Test
public void sorryButThisIsNotReallyDebatableToMe() {
// To me, it is *totally* reasonable to expect that
getSessionFactory() returns non-null here...
assert getSessionFactory() != null;
}
}
[/code]
So obviously this works. According to your definitions (I think) here
we have a private method on the superclass "visible" to the subclass.
At least it behaves in exactly the same way I was expecting
@BeforeClass directly on the private initSessionFactory() to work.
So perhaps you could explain where the difference lies in your mind?
[code]
class Parent {
private SessionFactory sessionFactory = initSessionFactory();
In the last examples you've sent you are following the Java visibility rules:
Case 1: you have a protected ctor which is visible to the subclass and
from there you invoke the private method => oke with Java
Case 2: you have the default public constructors and the
initialization block => oke with Java
while your initial example is just about making a parent private
method visible to a child class.
Now, considering that this discussion is just meant to reach a working
solution, I am still wondering why you really need that behavior.
bests,
./alex
--
.w( the_mindstorm )p.
TestNG co-founder
EclipseTestNG Creator
On 8/4/07, steve.ebersole <steven....@gmail.com> wrote:
>
"Really need" what behavior? The Hibernate test suite has many, many,
many test classes. Almost all of them need to build a SessionFactory,
with really pretty minimal differences between the classes (usually
the mappings to use is the only variance). Again, these previous
examples are all based off of your original trivial example meant to
illustrate you PoV. The Hibernate "base test" is really more like:
class abstract FunctionalTest implements IHookable {
private Configuration configuration;
private SessionFactory sessionFactory;
/**
* This is one of a few methods test classes can use to
* control configuration of the SessionFactory.
*/
protected abstract String[] getMappings();
...
protected Configuration getConfiguration() {
return configuration;
}
protected SessionFactory getSessionFactory() {
return sessionFactory;
}
@BeforeClass
private void initializeEnvironment() {
configuration = new Configuration();
for ( int i = 0, x = getMappings().length; i < x; i++ ) {
configuration.addResource( getMapping()[i] );
}
sessionFactory.buildSessionFactory();
}
@AfterClass
private void releaseEnvironment() {
if ( sessionFactory != null ) {
sessionFactory.close();
}
}
...
}
Again, to me these methods are simply part of the implementation
details of the superclass contract. Exposing them to subclasses by
making them visible serves no purpose except to confuse subclass
writers (do I need to manually initialize the environment myself? why
else would this be exposed as protected? ...).