| BMPEntityBeanTest.java |
package org.mockejb.test.entity;
import java.util.Collection;
import javax.naming.*;
import junit.framework.TestCase;
import org.easymock.MockControl;
import org.mockejb.*;
import org.mockejb.interceptor.*;
import org.mockejb.jndi.*;
/**
* Demonstrates BMP Entity bean support.
* MockEJB calls BMP entity beans same way with session beans,
* however finders have to be handled using aspects/interceptors framework.
* BMP finders always return primary key(s), so clients have to write
* interceptors to translate primary key to the entity.
*/
public class BMPEntityBeanTest extends TestCase {
// JNDI context and MockContainer instance used by all tests in this class
private MockContainer mockContainer;
private Context context;
private AspectSystem aspectSystem;
// We use PersonHome in all tests
private PersonHome personHome;
public BMPEntityBeanTest(String testName) {
super(testName);
}
/**
* Sets up our mock container, JNDI context and deploy the beans that we need.
*/
public void setUp() throws Exception {
// we use aspects in most of the tests here
aspectSystem = AspectSystemFactory.getAspectSystem();
// MockContextFactory becomes the primary JNDI provider
MockContextFactory.setAsInitial();
context = new InitialContext();
// Creating MockContainer deletes all aspects from AspectSystem and clears EntityDatabase
mockContainer = new MockContainer( context );
// Deploy the person bean
EntityBeanDescriptor personDescriptor =
new EntityBeanDescriptor( Person.JNDI_NAME,
PersonHome.class, Person.class, PersonBMPBean.class );
mockContainer.deploy( personDescriptor );
// Obtain personHome for use in the tests
personHome = (PersonHome)context.lookup(Person.JNDI_NAME);
}
public void tearDown() {
// cleanup JNDI settings
MockContextFactory.revertSetAsInitial();
}
/**
* Demonstrates how to setup BMP finder support with the help of
* interceptors. PersonFinderAspect (see the code at bottom of this file)
* ignores the PK values returned by the real finder and substitutes them
* with the Person entities that it creates.
* This can be used to provide mock data for testing as opposed to
* relying on the database.
*/
public void testFinderUsingAspect() throws Exception {
// add aspect that handles finders
aspectSystem.add( new PersonFinderAspect() );
Person person = personHome.findByName("John", "Doe" );
assertNotNull(person);
assertEquals("Doe", person.getLastName());
}
/**
* Demonstrates how to tell MockEJB to resolve the PKs returned by the
* finder without the use of interceptors.
*/
public void testFinderUsingEntityDatabase() throws Exception {
// Create mock entity
MockControl personBeanControl = MockControl.createControl( Person.class);
Person createdPerson = (Person) personBeanControl.getMock();
createdPerson.getId();
personBeanControl.setReturnValue(1L);
createdPerson.getFirstName();
personBeanControl.setReturnValue("John");
createdPerson.getLastName();
personBeanControl.setReturnValue("Doe");
personBeanControl.replay();
/* Add mock entity to the "database" so MockEJB could resolve the PKs returned by the finder.
* For BMP, MockEJB searches the EntityDatabase for every PK returned by the finder.
*/
mockContainer.getEntityDatabase().add( PersonHome.class, new Long(1), createdPerson );
PersonHome personHome = (PersonHome)context.lookup(Person.JNDI_NAME);
Person foundPerson = personHome.findByName("John", "Doe" );
assertEquals( createdPerson, foundPerson );
// Test the finder which returns the collection
Collection people = personHome.findByFirstName("John");
assertTrue( people.size()>0);
foundPerson = (Person)people.iterator().next();
assertEquals( createdPerson, foundPerson );
}
/**
* This test demonstrates how we can test BMP entities that
* indeed read something from the database.
* MockEJB does the following:
* it calls the finder, checks if the returned PK is in the EntityDatabase.
* If not, it creates a new entity instance and calls ejbLoad on it
*/
public void testFinderAndEjbLoad() throws Exception {
PersonHome personHome = (PersonHome)context.lookup(Person.JNDI_NAME);
/* BMPPersonBean finder always returns 1, so we're relying on this.
* We'll also rely on ejbLoad to populate the entity.
* BMPPersonBean.ejbLoad does not go to the database,
* it only sets the PK so we'll check that.
*/
Person foundPerson = personHome.findByName("John", "Doe" );
// did the ejbLoad work?
assertEquals( 1L, foundPerson.getId() );
// Test the finder which returns the collection
Collection people = personHome.findByFirstName("John");
assertTrue( people.size()>0);
foundPerson = (Person)people.iterator().next();
assertEquals( 1L, foundPerson.getId());
}
// *** Interceptors used by this test case
/**
* Handles findByName calls
*/
class PersonFinderAspect implements Aspect {
/**
* Intercept findByName method.
*/
public Pointcut getPointcut(){
// Note that we are intecepting target method on the bean
// as opposed to the interface method. Unlike in CMP case, we can do it
// because BMP entities have defined finder methods.
return new MethodPatternPointcut( "PersonBMPBean\\.ejbFindByName" );
}
public void intercept( InvocationContext invocationContext ) throws Exception {
Object [] paramVals = invocationContext.getParamVals();
// now create
invocationContext.setReturnObject( create( (String)paramVals[0], (String)paramVals[1] ) );
// We don't need to proceed to the next interceptor since we're done with the finder
}
/**
* Creates Person entity using "genericCreate" method which creates an
* instance of an entity without calling the actual "ejbCreate"
*/
private Person create( String firstName, String lastName ) throws Exception {
Context context = new InitialContext();
GenericHome home = (GenericHome)context.lookup(Person.JNDI_NAME);
Person person = (Person) home.genericCreate();
person.setFirstName(firstName);
person.setLastName(lastName);
return person;
}
}
}