ไปดู doc และ ตัวอย่างได้จาก Ejb3Unit homepage
หรือ
download Ejb3UnitSampleProject-2.0.0-RC-1.zip
how to import existing project in eclipse
วิธี1 จะก็อป jar ไฟล์เข้าโปรเจคเองก็ได้
วิธี2 จะ Properties > Java Build Path > libraries > Add External JARs ก็ได้
โดยโหลดจาก ejb3unit-jars.zip
extract ไฟล์ก่อนแล้วค่อย add นะ ย้ำ
จากนั้นลองรัน
Run As -> [Junit icon] Execute all ejb3 unit tests.
มันจะรัน 31 tests ผ่านโดยไม่มี errors
สร้าง new project เพื่อ test EJBs ของคุณ
ejbunit สร้าง on top of Junit ( ใช้ javaSE )
ไม่ต้อง export ก่อนรันเทส ejbunit จะ simulate environment
ทำ Part 2 ให้ work ก่อน
เพราะว่านี่จะทำต่อจาก Part 2 ( Eclipse/EJB/GlassFish/JPA )
ตอนนี้ก็มี Project titan-ejb ที่มี EJB module targeted for GlassFish
- มี entities Cabin, Customer, และ Phone
- มี stateless session bean ชื่อว่า TravelAgentBean และมี remote interface
- สร้าง new Java project ชื่อ titan-tests
add the external JARs for Ejb3Unit ให้เรียบร้อย
- บอก Eclipse ให้ reference unit test project (titan-tests) ไปยัง EJB module project (titan-ejb)
ทำให้สามารถเข้าถึง source classes ใน EJB module project ได้
add the titan-ejb project ไปยัง "Java Build Path" ในแท็บ "Projects"
และ add the titan-ejb project ใน "Project References"
- เทส Phone entity ก่อนละกัน
ก่อนอื่น เราต้อง override equals() กับ hashCode() ในคลาส Phone
เพราะ detached entity ต้อง"เท่ากับ" และสร้าง hash code เดียวกันกับ attached version
กลับไปเพิ่ม code เพื่อ override the methods ที่คลาส Phone ใน titan-ejb project
@Override
public boolean equals(Object other) {
if (other != null && other instanceof Phone) {
final Phone that = (Phone) other;
final EqualsBuilder builder = new EqualsBuilder();
builder.append(this.id, that.id);
builder.append(this.number, that.number);
return builder.isEquals();
}
return false;
}
@Override
public int hashCode() {
final HashCodeBuilder builder = new HashCodeBuilder();
builder.append(this.id);
builder.append(this.number);
return builder.toHashCode();
}
โค้ดที่เราเพิ่มไป มันใช้คลาส EqualsBuilder ( อยู่ใน commons-lang-2.4.jar : Apache Commons Lang library และอยู่ในไฟล์ ejb3unit-jars.zip ที่โหลดมาตะกี้ ) add มันใส่ build path ด้วย
ตอนนี้ titan-ejb project มี commons-lang-2.4.jar แต่ dependency มันจะไม่โดนแพ็คไปกับ EJB JAR file ตอน deploy ขึ้น application server (จะเจอ errors ประมาณว่า "class not found" ตอนรันบน application server)
สำหรับ GlassFish, ให้ก็อบ JAR file ที่ต้องใช้ไปที่ glassfish/domains/domain1/lib/ext/ (assuming your domain is domain1) มันจะ available สำหรับทุกๆ components ที่ deployed ไปยัง domain1.
กลับมายัง titan-tests project เพิ่ม class PhoneTest ( package com.titan.entitytests )
public class PhoneTest extends BaseEntityFixture<Phone> {
public PhoneTest() {
super(Phone.class);
}
}
คลาสนี้ แค่ใช้ default behavior ของคลาส BaseEntityFixture เพื่อเทสคลาส Phone
รันได้ละ คลิกขวา Run As -> JUnit Test จะมี 5/5 tests pass
testNothing() ซึ่งเป็น คลาสที่ inherit มา แล้วก็ 4 คลาสที่สร้างขึ้น
Configure Ejb3Unit
โดยใช้ ejb3unit.properties configuration file
New -> Source Folder ชื่อ "resources" ที่ level บนสุดของ titan-tests project
เพิ่ม file ejb3unit.properties
ejb3unit.inMemoryTest=true
ejb3unit.show_sql=true
## values are create-drop, create, update ##
ejb3unit.schema.update=create-drop
โค้ดนี้บอก Ejb3Unit ว่าให้จำลอง database ใน memory เพื่อแสดง SQL queries ที่ส่งไปยัง database บน console ( ไม่ต้องต่อกับ database จริง, ถ้าอยากต่อ database จริง ก็ config ในนี้แหละ ดูวิธีจาก Ejb3Unit documentation )
และ drop and create necessary tables สำหรับ entites ทุกครั้งที่ Ejb3Unit starts up
Unit testing entities manually
Ejb3Unit สนับสนุน automated test entities ที่เป็นแบบ one-to-many bidirectional associations ( เทสโดยใช้คลาส BaseEntityFixture )
แต่ไม่ support automated เทส entities ที่เป็นแบบ unidirectional associations ( ไปใช้คลาส PojoFixture แทน )
Mapping Customer-to-Phone ของเราเป็น one-to-many unidirectional เราจึงไม่สามารถใช้ BaseEntityFixture สำหรับคลาส Customer
เริ่มจาก สร้าง hashCode() และ equals() ในคลาส Customer
@Override
public boolean equals(Object other) {
if (other != null && other instanceof Customer) {
final Customer that = (Customer) other;
final EqualsBuilder builder = new EqualsBuilder();
builder.append(this.firstName, that.firstName);
builder.append(this.lastName, that.lastName);
builder.append(this.id, that.id);
return builder.isEquals();
}
return false;
}
@Override
public int hashCode() {
final HashCodeBuilder builder = new HashCodeBuilder();
builder.append(this.firstName);
builder.append(this.lastName);
builder.append(this.id);
return builder.toHashCode();
}
และสร้าง test class ตามนี้
public class CustomerTest extends PoJoFixture {เหมือนเดิม คลิกขวา Run As -> JUnit Test
private static final Class[] USED_ENTITIES = { Customer.class, Phone.class };
public CustomerTest() {
super( USED_ENTITIES );
}
public void testGetEntityManager() {
assertNotNull(this.getEntityManager());
}
public void testWriteCustomer() {
List<Customer> customers = generateTestCustomers();
// persist the graph and load it again
List<Customer> persisted = persist(customers);
List<Customer> allFromDB = findAll(Customer.class);
// assert the persisted graph and the loaded are equal
assertCollectionsEqual(persisted, allFromDB);
}
private List<Customer> generateTestCustomers() {
final List<Customer> customers = new ArrayList<Customer>();
Customer customer = new Customer();
customer.setFirstName( "Matthew" );
customer.setLastName( "Dailey" );
customer.addPhoneNumber( "+66851234567" );
customers.add( customer );
return customers;
}
// Manually delete customers with the entity manager so that
// the delete cascades to the dependent phone numbers.
private void deleteCustomers() {
EntityManager em = getEntityManager();
List<Customer> customers = findAll(Customer.class);
for ( Customer customer : customers ) {
em.remove( customer );
}
}
@Override
public void setUp() throws Exception {
super.setUp();
deleteCustomers();
deleteAll(Phone.class);
}
@Override
public void tearDown() throws Exception {
deleteCustomers();
deleteAll(Phone.class);
super.tearDown();
}
}
ปล. ต้องไปเพิ่ม method addPhoneNumber เข้า คลาส Customer เพื่อให้มันเรียก
customer.addPhoneNumber( "+66851234567" );ได้ด้วย
Unit testing session beans ========================================
Ejb3Unit เทส session beans ได้มากมายมาก ดูจากตัวอย่างที่โหลดมาได้ ( DIFieldSessionBeanTest.java )
ตอนนี้เราจะเทส TravelAgentBean
เพิ่ม functionality ไปยัง TravelAgentRemote interface:
@Remote
public interface TravelAgentRemote {
public void createCabin( Cabin cabin );
public Cabin findCabin( int id );
public List<Cabin> getAllCabins(); //
public int createCustomer( Customer customer );
public Collection<Phone> phoneNumbersForCust( int id );
public EntityManager getEm(); //
}
เราจะ test dependency injection ของ entity manager ที่ initialization timeand each of the methods. นี่คือวิธี implement method ใหม่ :
public EntityManager getEm() {
return this.manager;
}
@SuppressWarnings("unchecked")
public List<Cabin> getAllCabins() {
Query query = manager.createQuery( "SELECT c FROM Cabin c" );
return Collections.checkedList( query.getResultList(), Cabin.class );
}
ใน ejb-tests project, สร้างคลาส TravelAgentBeanTest ( package com.titan.sessionbeantests )
public class TravelAgentBeanTest extends BaseSessionBeanFixture<Travelagentbean> {
private static final Class[] usedBeans = { Cabin.class }; // Entity ที่เกี่ยวข้อง ต้องใส่ลงไปให้หมด ( ไม่งั้นจะเจอ java.lang.IllegalArgumentException: Unknown entity: หรือไม่ก็ EntityManager could not be initialized to load the enities [com.midterm.domain.Cm, com.midterm.domain.BidInvitation]. Cause: org.ejb3unit.hibernate.AnnotationException: Use of @OneToMany or @ManyToMany targeting an unmapped class: com.midterm.domain.BidInvitation.bids[com.midterm.domain.Bid] )
private static final CSVInitialDataSet<Cabin> CSV_SET =
new CSVInitialDataSet<Cabin>( Cabin.class, "testCabins.csv", "id", "name",
"deckLevel", "shipId", "bedCount" );
public TravelAgentBeanTest() {
// super(sessionBeanToTest, introspector, usedEntityBeans, initialData)
super( TravelAgentBean.class, usedBeans, new CabinEntityInitialDataSet(), CSV_SET ); //
}
public void testDependencyInjection() {
final TravelAgentBean toTest = this.getBeanToTest();
assertNotNull(toTest);
assertNotNull(toTest.getEm());
}
public void testLoadData() {
final TravelAgentBean travelAgentBean = this.getBeanToTest();
assertNotNull(travelAgentBean);
List<Cabin> cabins = travelAgentBean.getAllCabins();
assertNotNull(cabins);
System.out.println( "cabins has " + cabins.size() + " entries" );
assertEquals( 6, cabins.size() );
assertEquals( cabins.get(0), new Cabin( 1, "Cabin 8", 1 ));
assertEquals( cabins.get(1), new Cabin( 2, "Cabin 12", 1 ));
}
public static class CabinEntityInitialDataSet extends EntityInitialDataSet<Cabin> {
public CabinEntityInitialDataSet() {
super(Cabin.class);
}
public void create() {
this.add( new Cabin( 1, "Cabin 8", 1 ));
this.add( new Cabin( 2, "Cabin 12", 1 ));
}
}
}
นี่เป็น dependency injection test สองวิธีที่จะสร้าง entity test fixtures
วิธี1 โหลดจาก resources/testCabins.csv ( resources เป็น sources folder )
วิธี2 manually adding entities โดยใช้คลาส EntityInitialDataSet
ตัวอย่างข้างบนใส่ initial data ทั้งสองวิธี
ในไฟล์ csv ใส่อะไรประมาณนี้ลงไป
100,"Cabin 345",1,1,2
101,"Cabin 346",1,1,3
102,"Cabin 347",2,1,2
103,"Cabin 348",2,1,3
แล้วก็เพิ่มเทสลงไป
public void testCreateCabin() {สังเกตว่า เราสร้าง entity manager transaction manually
final TravelAgentBean travelAgentBean = this.getBeanToTest();
// Get list of cabins before we do the create
List<Cabin> cabinsBefore = travelAgentBean.getAllCabins();
assertEquals(6, cabinsBefore.size());
EntityManager manager = travelAgentBean.getEm();
EntityTransaction transaction = manager.getTransaction();
transaction.begin();
for ( int i = 0; i < 10; i++ ) {
Cabin cabin = new Cabin();
cabinsBefore.add( cabin );
cabin.setShipId(3);
cabin.setName("New cabin " + i);
cabin.setDeckLevel(5);
cabin.setBedCount(2);
travelAgentBean.createCabin(cabin);
}
transaction.commit();
List<Cabin> cabinsAfter = travelAgentBean.getAllCabins();
assertEquals(16, cabinsAfter.size());
assertCollectionsEqual(cabinsBefore, cabinsAfter);
}
ไม่งั้น ในเมธอด getAllCabins() ตอนเรา execute EJB QL query เพื่อ retrieve all persisted Cabins มันจะยัดลง database ไม่ได้
public void testFindCabin() {
final TravelAgentBean travelAgentBean = this.getBeanToTest();
// The cabin with name "Cabin 8" added in the create() method of the initial data
// set should have its ID generated as 118 by the time we get to this test case.
Cabin cabin = travelAgentBean.findCabin(118);
assertEquals(cabin, new Cabin(118, "Cabin 8", 1));
}
ref : mdailey
ความคิดเห็น