Å×½ºÆ® Àü¿ë ÀÛµ¿À¸·Î ´ÜÀ§ Å×½ºÆ® Çâ»ó½ÃÅ°±â
Nicholas
Lesiecki ¼ÒÇÁÆ®¿þ¾î ¿£Áö´Ï¾î, eBlox, Inc. 2002³â 5¿ù
Á¸°æ¹Þ´Â ÀÚ¹Ù ÇÁ·Î±×·¡¸ÓÀÌÀÚ XP Ä¿¹Â´ÏƼ ¸®´õÀÎ Nicholas Lesiecki´Â
Å×½ºÆ® ÄÉÀ̽º °í¸³È¿Í °ü·ÃÇÑ ¹®Á¦¸¦ ¼Ò°³ÇÏ°í mock °´Ã¼¿Í AspectJ¸¦ ÀÌ¿ëÇÏ¿© Á¤¹ÐÇÏ°í °·ÂÇÑ ´ÜÀ§
Å×½ºÆ®¸¦ °³¹ßÇÏ´Â ¹æ¹ýÀ» ¼³¸íÇÑ´Ù.
Extreme Programming (XP)¿¡ ´ëÇÑ ÃÖ±ÙÀÇ °ü½ÉÀº Æ÷Æð¡´É¼ºÀÌ ³óÈÄÇÑ ¹®Á¦ÀÎ ´ÜÀ§ Å×½ºÆðú
Å×½ºÆ® ¿ì¼± ¼³°è·Î ¿Å°Ü°¬´Ù. ¼ÒÇÁÆ®¿þ¾î ˜Þµé?XPÀÇ °ü·Ê¸¦ äÅÃÇÔ¿¡ µû¶ó ¸¹Àº °³¹ßÀÚµéÀº Ç°Áú°ú ¼Óµµ Çâ»óÀ»
°æÇèÇÏ°Ô µÇ¾ú´Ù. ÇÏÁö¸¸ ÁÁÀº ´ÜÀ§ Å×½ºÆ®¸¦ ÀÛ¼ºÇÏ´Â °ÍÀº ½Ã°£°ú ³ë·ÂÀ» ¿ä±¸ÇÑ´Ù. °¢°¢ÀÇ ´ÜÀ§(unit)´Â
´Ù¸¥ ´ÜÀ§µé°ú Çùµ¿Çϱ⠶§¹®¿¡ ´ÜÀ§ Å×½ºÆ®¸¦ ÀÛ¼ºÇÏ´Â °ÍÀº »ó´ç·®ÀÇ ¼³Á¤ Äڵ带 Æ÷ÇÔ ÇÒ ¼ö Àֱ⠶§¹®ÀÌ´Ù.
ÀÌ°ÍÀº Å×½ºÆ®¸¦ °ªºñ½Ñ °ÍÀ¸·Î ¸¸µé°í ¾î¶² °æ¿ì¿¡´Â ±×¿Í °°Àº Å×½ºÆ®´Â ±¸ÇöÀÌ °ÅÀÇ ºÒ°¡´ÉÇÏ´Ù.
XP ¿¡¼, ´ÜÀ§ Å×½ºÆ®(unit test)´Â ÅëÇÕ Å×½ºÆ® (integration)¿Í ¼ö¶ô
Å×½ºÆ®(acceptance test)¸¦ º¸ÃæÇÏ´Â °ÍÀÌ´Ù. ÀÌµé µÎ°³ÀÇ Å×½ºÆ® À¯ÇüÀº °³º° ÆÀµéÀÌ ´ã´çÇϰųª °³º°
ÀÛµ¿À¸·Î¼ ¹Þ¾Æµé¿©Áø´Ù. ÇÏÁö¸¸ ´ÜÀ§ Å×½ºÆ®´Â Å×½ºÆ® µÇ¾î¾ß ÇÒ ÄÚµå¿Í µ¿½Ã¿¡ ÀÛ¼ºµÈ´Ù. ÀÓ¹ÚÇÑ µ¥µå¶óÀΰú
µÎÅëÀ» ¼ö¹ÝÇÏ´Â ´ÜÀ§ Å×½ºÆ®¿¡ Á÷¸éÇÏ¸é ¾ûÅ͸® Å×½ºÆ®¸¦ ÀÛ¼ºÇÏ°Ô µÇ°Å³ª Å×½ºÆ® ¶§¹®¿¡ ±«·ÓÈûÀ» ´çÇϰԵȴÙ.
ÀÌ ±ÛÀ» Àбâ Àü¿¡..
ÀÌ ±ÛÀº AspectJ¸¦ ÀÌ¿ëÇÑ ´ÜÀ§ Å×½ºÆ®¿¡ ÃÊÁ¡À» ¸ÂÃá´Ù. ÀÌ ±ÛÀ» Àд µ¶ÀÚ´Â ±âº»ÀûÀÎ
´ÜÀ§ Å×½ºÆ® ±â¼úÀ» ¼÷ÁöÇÏ°í ÀÖ¾î¾ß ÇÑ´Ù. AspectJ¿¡ Àͼ÷ÇÏÁö ¾Ê´Ù¸é, AspectJ ¼Ò°³ °ü·Ã
±ÛÀ» Àб⠹ٶõ´Ù (Âü°íÀÚ·á).
AspectJ ±â¼úÀº º¹ÀâÇÏÁö´Â ¾ÊÁö¸¸ aspect ÁöÇâ ÇÁ·Î±×·¡¹ÖÀº º¹ÀâÇÒ ¼ö ÀÖ´Ù. ¿¹Á¦¸¦
½ÇÇàÇÏ·Á¸é ½Ã½ºÅÛ¿¡ Ant¸¦
¼³Ä¡ÇØ¾ß ÇÑ´Ù. |
Mock °´Ã¼´Â ÀÌ·¯ÇÑ µô·¹¸¶¸¦ Ǫ´Âµ¥ µµ¿òÀÌ µÈ´Ù. Mock °´Ã¼ Å×½ºÆ®´Â µµ¸ÞÀÎ ÀÇÁ¸¼ºÀ» Å×½ºÆÿ¡¸¸
»ç¿ëµÇ´Â mock ±¸ÇöÀ¸·Î ´ëüÇÑ´Ù. ÇÏÁö¸¸ ÀÌ·¯ÇÑ Àü·«Àº ¿ø°Ý ½Ã½ºÅÛ¿¡¼ÀÇ ´ÜÀ§ Å×½ºÆ® °°Àº Ưº°ÇÑ »óȲ¿¡
±â¼úÀûÀÎ µµÀüÀÌ µÈ´Ù. AspectJ´Â ÀüÅëÀûÀÎ °´Ã¼ ÁöÇâ ±â¼úÀÌ ½ÇÆÐÇÏ´Â ºÐ¾ß¿¡¼ Å×½ºÆ® Àü¿ë ÀÛµ¿À» ´ëüÇÒ
¼ö ÀÖµµ·Ï ÇÔÀ¸·Î¼ ´ÜÀ§ Å×½ºÆÃÀÇ ¶Ç ´Ù¸¥ ¹æÇâÀ» Á¦½ÃÇÏ°í ÀÖ´Ù.
ÀÌ ±Û¿¡¼´Â ´ÜÀ§ Å×½ºÆ®¸¦ ÀÛ¼ºÇÏ´Â °ÍÀÌ ¾î·Æ°íµµ ÇÊ¿äÇÑ »óȲÀ» ½ÃÇèÇÏ°Ô µÈ´Ù. EJB ±â¹Ý ¾ÖÇø®ÄÉÀ̼ÇÀÇ
Ŭ¶óÀ̾ðÆ® ÄÄÆ÷³ÍÆ®¿¡ ´ëÇÑ ´ÜÀ§ Å×½ºÆ®¸¦ ½ÇÇàÇÏ´Â °ÍÀ¸·Î ½ÃÀÛÇÏ°Ú´Ù. ¿ø°Ý Ŭ¶óÀ̾ðÆ® °´Ã¼¿¡ ´ëÇÑ ´ÜÀ§ Å×½ºÆ®
½Ã ¹ß»ýÇÒ ¼ö ÀÖ´Â ¹®Á¦¸¦ ¿¹Á¦¸¦ µé¾î ¼³¸íÇÒ °ÍÀÌ´Ù. ÀÌ·¯ÇÑ ¹®Á¦µéÀ» ÇØ°áÇϱâ À§Çؼ AspectJ¿Í mock
°´Ã¼¿¡ ÀÇÁ¸ÇÏ´Â µÎ°³ÀÇ »õ·Î¿î Å×½ºÆ® ¼³Á¤À» °³¹ßÇÒ °ÍÀÌ´Ù.
InÄÚµå »ùÇÃÀ» ÀÌ¿ëÇÏ·Á¸é ¿¹Á¦
¾ÖÇø®ÄÉÀ̼ÇÀ» ¼³Ä¡ÇØ¾ß ÇÑ´Ù.
´ÜÀ§ Å×½ºÆ® ¿¹Á¦ ÀÌ
¿¹Á¦´Â EJB Ŭ¶óÀ̾ðÆ®¿ë Å×½ºÆ®·Î ±¸¼ºµÇ¾î ÀÖ´Ù. ÀÌ ÄÉÀ̽º ½ºÅ͵𿡼 ¹ß»ýÇÏ´Â ¸¹Àº ¹®Á¦µéÀº À¥ ¼ºñ½º,
JDBC, facade¸¦ ÅëÇÑ ·ÎÄà ¾ÖÇø®ÄÉÀ̼ÇÀÇ "¿ø°Ý" ºÎºÐÀ» È£ÃâÇÏ´Â Äڵ忡 Àû¿ëµÉ ¼ö ÀÖ´Ù.
¼¹öÃø CustomerManager EJB´Â µÎ ±â´ÉÀ» ¼öÇàÇÑ´Ù: °í°´ÀÇ À̸§À»
°Ë»çÇÏ°í »õ·Î¿î °í°´ À̸§À» ¿ø°Ý ½Ã½ºÅÛ¿¡ µî·ÏÇÑ´Ù. Listing 1Àº
CustomerManager °¡ Ŭ¶óÀ̾ðÆ®¿¡ ³ëÃâÇÏ´Â ÀÎÅÍÆäÀ̺ÀÌ´? Listing 1. CustomerManagerÀÇ ¿ø°Ý ÀÎÅÍÆäÀ̽º
public interface CustomerManager extends EJBObject {
/**
* Returns a String[] representing the names of customers in the system
* over a certain age.
*/
public String[] getCustomersOver(int ageInYears) throws RemoteException;
/**
* Registers a new customer with the system. If the customer already
* exists within the system, this method throws a NameExistsException.
*/
public void register(String name)
throws RemoteException, NameExistsException;
}
|
Ŭ¶óÀ̾ðÆ® ÄÚµåÀÎ ClientBean Àº ¹Ýµå½Ã °°Àº ¸Þ¼Òµå¸¦ ³ëÃâÇÏ¸é¼ ±×µéÀÇ
±¸ÇöÀ» CustomerManager ¿¡ º¸³½´Ù. (Listing 2) Listing 2. EJB Ŭ¶óÀ̾ðÆ® ÄÚµå
public class ClientBean {
private Context initialContext;
private CustomerManager manager;
/**
* Includes standard code for referencing an EJB.
*/
public ClientBean() throws Exception{
initialContext = new InitialContext();
Object obj =
initialContext.lookup("java:comp/env/ejb/CustomerManager");
CustomerManagerHome managerHome = (CustomerManagerHome)obj;
/*Resin uses Burlap instead of RMI-IIOP as its default
* network protocol so the usual RMI cast is omitted.
* Mock Objects survive the cast just fine.
*/
manager = managerHome.create();
}
public String[] getCustomers(int ageInYears) throws Exception{
return manager.getCustomersOver(ageInYears);
}
public boolean register(String name) {
try{
manager.register(name);
return true;
}
catch(Exception e){
return false;
}
}
}
|
³ª´Â ÀÌ ´ÜÀ§¸¦ ÃÖ´ëÇÑ °£´ÜÇÏ°Ô ÇÏ¿© Å×½ºÆ®¿¡ ÁýÁßÇÒ ¼ö ÀÖµµ·Ï Çß´Ù.
ClientBean ÀÇ ÀÎÅÍÆäÀ̽º´Â CustomerManager ÀÇ
ÀÎÅÍÆäÀ̽º¿Í ¾à°£ ´Ù¸£´Ù. ClientManager ¿Í´Â ´Ù¸£°Ô
ClientBean 's register() ¸Þ¼Òµå´Â
ºÎ¿ï(boolean)À» ¸®ÅÏÇÏ°í °í°´ÀÌ ÀÌ¹Ì Á¸ÀçÇÏ°í ÀÖÀ¸¸é ¿¹¿Ü¸¦ ´øÁöÁö ¾Ê´Â´Ù. ÀÌ°ÍÀº ÁÁÀº ´ÜÀ§ Å×½ºÆ®¶ó´Â
°ÍÀ» ÀÔÁõÇÏ´Â °ÍÀÌ´Ù.
Listing 3ÀÇ ÄÚµå´Â JUnitÀ¸·Î ClientBean ¿ë Å×½ºÆ®¸¦ ±¸ÇöÇÑ
°ÍÀÌ´Ù. ¼¼ °³ÀÇ Å×½ºÆ® ¸Þ¼Òµå°¡ Àִµ¥, Çϳª´Â getCustomers() ¿ë ÀÌ°í µÎ
°³´Â register() ¿ë ÀÌ´Ù. (¼º°ø°ú ½ÇÆÐÀÇ µÎ °æ¿ì).
getCustomers() ¸¦ ¸Ã°í ÀÖ´Â Å×½ºÆ®´Â 55 ¾ÆÀÌÅÛ ¸®½ºÆ®¸¦ ¸®ÅÏÇÏ°í
register() ´Â EXISTING_CUSTOMER ¿¡ ´ëÇØ
false ¸¦, NEW _CUSTOMER ¿¡ ´ëÇØ
true ¸¦ ¸®ÅÏÇÑ´Ù. Listing 3.
ClientBean¿ë ´ÜÀ§ Å×½ºÆ®
//[...standard JUnit methods omitted...]
public static final String NEW_CUSTOMER = "Bob Smith";
public static final String EXISTING_CUSTOMER = "Philomela Deville";
public static final int MAGIC_AGE = 35;
public void testGetCustomers() throws Exception {
ClientBean client = new ClientBean();
String[] results = client.getCustomers(MAGIC_AGE);
assertEquals("Wrong number of client names returned.",
55, results.length);
}
public void testRegisterNewCustomer() throws Exception{
ClientBean client = new ClientBean();
//register a customer that does not already exist
boolean couldRegister = client.register(NEW_CUSTOMER);
assertTrue("Was not able to register " + NEW_CUSTOMER, couldRegister);
}
public void testRegisterExistingCustomer() throws Exception{
ClientBean client = new ClientBean();
//register a customer that DOES exist
boolean couldNotRegister = ! client.register(EXISTING_CUSTOMER);
String failureMessage = "Was able to register an existing customer ("
+ EXISTING_CUSTOMER + "). This should not be " +
"possible."
assertTrue(failureMessage, couldNotRegister);
}
|
Ŭ¶óÀ̾ðÆ®°¡ ¿¹°ßµÈ °á°ú¸¦ ¸®ÅÏÇϸé Å×½ºÆ®´Â Åë°úÇÑ´Ù. ÀÌ Å×½ºÆ®°¡ ¸Å¿ì ´Ü¼øÇÑ ¸¸Å °°Àº ÀýÂ÷¸¦ EJB
ÄÄÆ÷³ÍÆ®·ÎÀÇ È£Ãâ¿¡ ±â¹ÝÇÏ¿© ¾Æ¿ôDzÀ» ¸¸µå´Â ¼ºí¸´ °°Àº Á»´õ º¹ÀâÇÑ Å¬¶óÀ̾ðÆ®¿¡ Àû¿ëÇÏ´Â ¹æ¹ýÀ» ½±°Ô »ó»óÇÒ
¼ö ÀÖ´Ù.
»ùÇà ¾ÖÇø®ÄÉÀ̼ÇÀ» ÀÌ¹Ì ¼³Ä¡Çß´Ù¸é ¿¹Á¦ µð·ºÅ丮ÀÇ ant basic ¸í·É¾î·Î Àá±ñ
Å×½ºÆ®¸¦ ÇغÁµµ ÁÁ´Ù.
µ¥ÀÌÅÍ ÀÇÁ¸ Å×½ºÆ®ÀÇ
¹®Á¦Á¡ À§ Å×½ºÆ®¸¦ ¸î Â÷·Ê ½ÇÇàÇÑ ÈÄ¿¡ ÀÏ°ü¼º ¾ø´Â °á°ú¸¦ ¾Ë°ÔµÈ´Ù: °¡²ûÀº Å×½ºÆ®°¡
Åë°úÇÏ°í °¡²ûÀº ±×·¸Áö ¾Ê´Ù. ºñ¿µ¼Ó¼ºÀÇ ¿øÀÎÀº Ŭ¶óÀ̾ðÆ®ÀÇ ±¸ÇöÀÌ ¾Æ´Ñ EJB ÄÄÆ÷³ÍÆ®ÀÇ ±¸Çö¿¡ ÀÖ´Ù.
¿¹Á¦¿¡¼ EJB ÄÄÆ÷³ÍÆ®´Â ºÒÈ®½ÇÇÑ ½Ã½ºÅÛ »óȲÀ» ½Ã¹Ä·¹ÀÌÆÃÇÑ´Ù. Å×½ºÆ® µ¥ÀÌÅÍÀÇ ºñ¿µ¼Ó¼ºÀº ´Ü¼øÇÏ°í µ¥ÀÌÅÍ
Áß½ÉÀÇ Å×½ºÆ®¸¦ ±¸ÇöÇÒ ¶§ ½ÇÁ¦ ¹®Á¦¿¡ ³ªÅ¸³´Ù. ¶Ç ´Ù¸¥ Å« ¹®Á¦´Â Å×½ºÆ®¸¦ Áߺ¹ÇØ¾ß ÇÑ´Ù´Â µ¥ ÀÖ´Ù.
µ¥ÀÌÅÍ
°ü¸® µ¥ÀÌÅÍ¿¡¼ ºÒÈ®½Ç¼ºÀ» ±Øº¹ÇÏ´Â ½¬¿î ¹æ¹ýÀº µ¥ÀÌÅÍÀÇ »óŸ¦ °ü¸®ÇÏ´Â °ÍÀÌ´Ù. ´ÜÀ§
Å×½ºÆ®¸¦ ½ÇÇàÇϱâ Àü¿¡ ½Ã½ºÅÛ¿¡ 55°³ÀÇ °í°´ ±â·ÏÀÌ ÀÖ´Ù´Â °ÍÀ» È®½ÅÇÑ´Ù¸é
getCustomers() Å×½ºÆ®ÀÇ ½ÇÆд µ¥ÀÌÅÍ ÀÚüÀÇ ¹®Á¦¶ó±â º¸´Ù´Â ÄÚµåÀÇ
°áÇÔÀ̶ó´Â °ÍÀ» ³ªÅ¸³½´Ù. ÇÏÁö¸¸ µ¥ÀÌÅÍÀÇ »óŸ¦ °ü¸®ÇÏ´Â °ÍÀº ±× ÀÚü·Î ¹®Á¦¸¦ ¾ß±âÇÒ ¼ö ÀÖ´Ù. Å×½ºÆ®¸¦
½ÇÇàÇϱâ Àü¿¡ ½Ã½ºÅÛÀÌ Æ¯Á¤ Å×½ºÆ®¿¡ ´ëÇØ Á¤È®ÇÑ »óÅ¿¡ ÀÖ´ÂÁö¸¦ È®ÀÎÇØ¾ß ÇÑ´Ù. ²ÙÁØÈ÷ ÁöÄѺ¸Áö ¾ÊÀ¸¸é ÇÑ
Å×½ºÆ®ÀÇ °á°ú´Â ´ÙÀ½ Å×½ºÆ®°¡ ½ÇÆÐÇÏ´Â ¹æÇâÀ¸·Î ½Ã½ºÅÛ »óŸ¦ º¯°æÇÒ ¼ö ÀÖ´Ù.
ÀÌ ¹®Á¦¿¡ ´ëÇؼ °øÀ¯µÈ ¼³Á¤ Ŭ·¡½º³ª ¹èÄ¡ ÀÎDz ÇÁ·Î¼¼½º(batch-input process)¸¦ »ç¿ëÇÒ
¼ö ÀÖ´Ù. ÇÏÁö¸¸ ÀÌ µÎ °¡Áö Á¢±Ù¹æ½ÄÀº ±â¹Ý±¸Á¶¿¡ ´ëÇÑ ¸·´ëÇÑ ÅõÀÚ°¡ ÀÖ¾î¾ß ÇÑ´Ù. ¿©·¯ºÐÀÇ ¾ÖÇø®ÄÉÀ̼ÇÀÌ
ÀÏÁ¤ÇÑ À¯ÇüÀÇ ÀúÀå »óÅ·ΠÁö¼ÓµÈ´Ù¸é Á»´õ ½É°¢ÇÑ ¹®Á¦¿¡ Á÷¸éÇÑ °ÍÀÌ´Ù. µ¥ÀÌÅ͸¦ ÀúÀå ½Ã½ºÅÛ¿¡ Ãß°¡ÇÏ´Â °ÍÀº
º¹ÀâÇØ Áú ¼ö ÀÖ°í ºó¹øÇÑ »ðÀÔ°ú »èÁ¦´Â Å×½ºÆ® ½ÇÇàÀ» ´ÊÃâ ¼ö ÀÖ´Ù.
°í±Þ Å×½ºÆ®
ÀÌ ±ÛÀº ´ÜÀ§ Å×½ºÆ®¿¡ ÃÊÁ¡À» ¸ÂÃß¾úÁö¸¸ ÅëÇÕ ¹× ÇÔ¼ö Å×½ºÆ® ¶ÇÇÑ ºü¸¥°³¹ß°ú °íÇ°Áú¿¡ ÀÖ¾î¼
Áß¿äÇÏ´Ù. °í±Þ Å×½ºÆ®´Â ½Ã½ºÅÛÀÇ end-to-end ÅëÇÕÀ» °¡´ÉÇÏ°Ô ÇÏ´Â ¹Ý¸é Àú¼öÁØ ´ÜÀ§ Å×½ºÆ®´Â
°³º° ÄÄÆ÷³ÍÆ®¿¡¸¸ °¡´ÉÇÏ´Ù. µÎ °³ ¸ðµÎ ´Ù¸¥ »óȲ¿¡¼
À¯¿ëÇÏ´Ù. |
»óÅ °ü¸®¿¡ °üÇÑ ¹®Á¦¿¡ ¸Âµü¶ß¸®´Â °Íº¸´Ù ´õ ³ª»Û °ÍÀº ±×¿Í °°Àº °ü¸®°¡ ÀüÇô ºÒ°¡´ÉÇÑ »óȲ¿¡ Á÷¸éÇßÀ»
¶§ÀÌ´Ù. ¿©·¯ºÐÀº ¾Æ¸¶µµ Á¦ »ïÀÚ ¼ºñ½º¸¦ À§ÇØ Å¬¶óÀ̾ðÆ® Äڵ带 Å×½ºÆ® ÇÒ ¶§ ÀÌ¿Í°°Àº »óȲ¿¡ ³õÀÌ°Ô µÈ´Ù.
Àбâ Àü¿ë ¼ºñ½º´Â ½Ã½ºÅÛ »óŸ¦ º¯°æÇÏ´Â ±â´ÉÀ» ³ëÃâÇÏÁö ¾Ê´Â´Ù. ¿¹¸¦ µé¾î ¶óÀ̺ê ÇÁ·Î¼¼½Ì Å¥¿¡ Å×½ºÆ®
¸í·ÉÀ» º¸³»´Â °ÍÀº ÁÁÀº »ý°¢ÀÌ ¾Æ´Ï´Ù.
ÀÌÁß ³ë·Â ½Ã½ºÅÛ
»óÅ¿¡ ´ëÇÑ ¿Ïº®ÇÑ Á¦¾î±ÇÀÌ ÀÖ´ÙÇÏ´õ¶óµµ »óÅ ±â¹ÝÀÇ Å×½ºÆÃÀº ¿øÄ¡ ¾Ê´Â Áߺ¹ÀÇ Å×½ºÆ® ³ë·ÂÀ» ¿äÇÑ´Ù. °°Àº
Å×½ºÆ®¸¦ µÎ¹ø ¾²±â¸¦ ´©°¡ ¿øÇϰڴ°¡.
ÀÌÁ¦ ¿¹Á¦ Å×½ºÆ® ¾ÖÇø®ÄÉÀ̼ÇÀ» º¸ÀÚ. CustomerManager EJB
ÄÄÆ÷³ÍÆ®¸¦ Á¦¾îÇÑ´Ù°í Çϸé, ÀÌ¹Ì ÀÌ°ÍÀÌ ¿Ã¹Ù¸£°Ô ÀÛµ¿ÇÑ´Ù´Â °ÍÀ» È®ÀÎÇÏ´Â Å×½ºÆ®µµ °®°í ÀÖÀ» °ÍÀÌ´Ù. ³»
Ŭ¶óÀ̾ðÆ® ÄÚµå´Â »õ·Î¿î °í°´À» ½Ã½ºÅÛ¿¡ Ãß°¡ÇÒ ¶§ ·ÎÁ÷ÀÌ °³ÀÔµÈ ¾î¶² °Íµµ ¼öÇàÇÏÁö ¾Ê´Â´Ù; ÀÌ°ÍÀº °£´ÜÈ÷
¿ÀÆÛ·¹À̼ÇÀ» CustomerManager ¿¡ º¸³½´Ù.
°°Àº µ¥ÀÌÅÍ¿¡ ´ëÇØ ´Ù¸¥ ÀÀ´äÀ» ÁÖ±â À§ÇØ CustomerManager ÀÇ ±¸ÇöÀ»
º¯È½ÃŲ´Ù¸é º¯È¸¦ Æ®·¡Å·Çϱâ À§ÇØ µÎ°¡ Áö Å×½ºÆ®¸¦ ¹Ù²Ù¾î¾ß ÇÑ´Ù. ÀÌ°ÍÀº Áߺ¹ Å×½ºÆ®ÀÇ ±â¹Ì°¡ º¸ÀδÙ.
´ÙÇàÈ÷ Áߺ¹ÀÌ ºÒÇÊ¿äÇÏ´Ù. ClientBean ÀÌ
CustomerManager ¿Í Á¤È®ÇÏ°Ô Åë½ÅÇÏ°í ÀÖ´Ù´Â °Í¸¸ È®ÀÎÇÒ ¼ö ÀÖ´Ù¸é,
ClientBean ÀÌ ¿øÇÏ´Â ´ë·Î ÀÛµ¿ÇÏ°í ÀÖ´Ù´Â ÃæºÐÇÑ È®½ÅÀÌ µÈ´Ù. Mock °´Ã¼
Å×½ºÆÃÀ¸·Î ÀÌ·¯ÇÑ Á¾·ùÀÇ È®ÀÎ ÀÛ¾÷À» Á¤È®È÷ ¼öÇàÇÒ ¼ö ÀÖ´Ù.
Mock °´Ã¼
Å×½ºÆà Mock °´Ã¼µéÀº Áö³ªÄ¡°Ô ¸¹Àº ´ÜÀ§ Å×½ºÆ®¸¦ ¹æÁöÇÑ´Ù. Mock °´Ã¼
Å×½ºÆ®µéÀº mock ±¸Çö°úÀÇ ½ÇÁ¦ÀûÀÎ Çù·ÂÀÚÀÌ´Ù. mock ±¸ÇöÀº Å×½ºÆ® µÈ Ŭ·¡½º¿Í collaborator°¡
Á¤È®ÇÏ°Ô ±³·ùÇÏ°í ÀÖ´Ù´Â °ÍÀ» ½±°Ô È®ÀÎÇØÁØ´Ù. °£´ÜÇÑ ¿¹Á¦¸¦ ÅëÇØ ÀÌ°ÍÀÇ ¾î¶»°Ô ÀÛµ¿ÇÏ´ÂÁö¸¦ ¼³¸íÇÏ°Ú´Ù.
¿ì¸®°¡ Å×½ºÆ®ÇÏ´Â ÄÚµå´Â Ŭ¶óÀ̾ðÆ®-¼¹ö µ¥ÀÌÅÍ °ü¸® ½Ã½ºÅÛ¿¡¼ °´Ã¼ ¸®½ºÆ®¸¦ Áö¿î´Ù. Listing 4´Â
Å×½ºÆ®ÇÏ°í ÀÖ´Â ¸Þ¼ÒµåÀÌ´Ù: Listing 4. Å×½ºÆ® ¸Þ¼Òµå
public interface Deletable {
void delete();
}
public class Deleter {
public static void delete(Collection deletables){
for(Iterator it = deletables.iterator(); it.hasNext();){
((Deletable)it.next()).delete();
}
}
}
|
½¬¿î ´ÜÀ§ Å×½ºÆ®´Â ½ÇÁ¦ Deletable À» ¸¸µé°í ±×·±´ÙÀ½
Deleter.delete() À» È£ÃâÇÑ ÈÄ ÀÌ°ÍÀÌ »ç¶óÁø´Ù´Â °ÍÀ» È®ÀÎÇÑ´Ù. mock
°´Ã¼¸¦ ÀÌ¿ëÇÏ¿© Deleter ¸¦ Å×½ºÆ®Çϱâ À§ÇØ
Deletable À» ±¸ÇöÇÏ´Â mock °´Ã¼¸¦ ÀÛ¼ºÇØ¾ß ÇÑ´Ù. (Listing 5):
Listing 5. mock °´Ã¼ Å×½ºÆ®
public class MockDeletable implements Deletable{
private boolean deleteCalled;
public void delete(){
deleteCalled = true;
}
public void verify(){
if(!deleteCalled){
throw new Error("Delete was not called.");
}
}
}
|
´ÙÀ½¿¡´Â Deleter ÀÇ ´ÜÀ§ Å×½ºÆ®¿¡ mock °´Ã¼¸¦ »ç¿ëÇÑ´Ù(Listing
6): Listing 6. mock °´Ã¼¸¦ »ç¿ëÇÏ´Â Å×½ºÆ®
¸Þ¼Òµå
public void testDelete() {
MockDeletable mock1 = new MockDeletable();
MockDeletable mock2 = new MockDeletable();
ArrayList mocks = new ArrayList();
mocks.add(mock1);
mocks.add(mock2);
Deleter.delete(mocks);
mock1.verify();
mock2.verify();
}
|
½ÇÇàÇÒ ¶§ ÀÌ Å×½ºÆ®´Â Deleter °¡ ¼º°øÀûÀ¸·Î Ä÷º¼ÇÀÇ °¢ °´Ã¼µé¿¡ ´ëÇØ
delete() À» ¼º°øÀûÀ¸·Î È£ÃâÇß´Ù´Â °ÍÀ» È®ÀÎÇÑ´Ù. ÀÌ·¯ÇÑ ¹æ½ÄÀ¸·Î, mock °´Ã¼
Å×½ºÆ®´Â Å×½ºÆ®µÈ Ŭ·¡½ºÀÇ ÁÖº¯À» Á¤¹ÐÇÏ°Ô Á¦¾îÇÏ°í ´ÜÀ§°¡ ±×µé°ú Á¤È®È÷ ±³·ùÇÑ´Ù´Â °ÍÀ» È®ÀÎÇÑ´Ù.
mock °´Ã¼ÀÇ
ÇÑ°è °´Ã¼ ÁöÇâ ÇÁ·Î±×·¡¹ÖÀº Å×½ºÆ®µÈ Ŭ·¡½º°¡ ½ÇÇàµÉ ¶§ mock °´Ã¼ Å×½ºÆ®ÀÇ ¿µÇâÀ»
Á¦ÇÑÇÑ´Ù. ¿¹¸¦µé¾î, ¾à°£ ´Ù¸¥ delete() ¸Þ¼Òµå¸¦ Å×½ºÆ®ÇÑ´Ù¸é ¿ì¸®ÀÇ Å×½ºÆ®´Â
±×·¸°Ô ½±°Ô mock °´Ã¼µéÀ» Á¦°øÇÒ ¼ö ¾ø´Ù. ´ÙÀ½ ¸Þ¼Òµå´Â mock °´Ã¼¸¦ ÀÌ¿ëÇÏ¿© Å×½ºÆ®ÇϱⰡ
¾î·Æ´Ù: Listing 7. ¾î·Á¿î ¸Þ¼Òµå
public static void deleteAllObjectMatching(String criteria){
Collection deletables = fetchThemFromSomewhere(criteria);
for(Iterator it = deletables.iterator(); it.hasNext();){
((Deletable)it.next()).delete();
}
}
|
mock °´Ã¼ Å×½ºÆà ¸Þ¼ÒµåÀÇ ÁöÁöÀÚ´Â À§¿Í °°Àº ¸Þ¼Òµå´Â Á»´õ "mock Ä£ÈÀûÀÎ" °ÍÀÌ µÉ ¼ö ÀÖµµ·Ï
À§¿Í °°Àº ¸Þ¼Òµå´Â ¸®ÆÑÅ丮 µÇ¾î¾ß ÇÑ´Ù°í ÁÖÀåÇÑ´Ù. ¸®ÆÑÅ丵Àº Á»´õ À¯¿¬ÇÑ µðÀÚÀÎÀÎ cleaner°¡ µÈ´Ù. Àß
¼³°èµÈ ½Ã½ºÅÛÀÇ °æ¿ì °¢ ´ÜÀ§´Â Á¤ÀÇ°¡ ÀßµÈ ÀÎÅÍÆäÀ̽º¸¦ ÅëÇØ ÀÌ°ÍÀÇ ÄÜÅؽºÆ®¿Í ±³·ùÇÑ´Ù.
ÇÏÁö¸¸ Àß ¼³°èµÈ ½Ã½ºÅÛÀÏÁö¶óµµ Å×½ºÆ®°¡ ÄÜÅؽºÆ®¿¡ ½±°Ô ¿µÇâÀ» ÁÙ ¼ö ¾ø´Â °æ¿ì°¡ ÀÖ´Ù. ÀÌ·¯ÇÑ Çö»óÀº
Äڵ尡 Àü¿ªÀûÀ¸·Î ¾×¼¼½º °¡´ÉÇÑ ¸®¼Ò½º¿¡¼ È£ÃâÇÒ ¶§ ¸¶´Ù ¹ß»ýÇÑ´Ù. ¿¹¸¦µé¾î Á¤Àû ¸Þ¼Òµå·ÎÀÇ È£ÃâÀº È®ÀÎ ¶Ç´Â
´ëü°¡ ¾î·Æ´Ù.
Mock °´Ã¼´Â Å×½ºÆÃÀÌ µµ¸ÞÀΠŬ·¡½º¿Í °ø¿ë ÀÎÅÍÆäÀ̽º¸¦ °øÀ¯ÇÏ´Â Å×½ºÆ® Ŭ·¡½º °£ÀÇ ¼öµ¿ ´ëü¿¡
±â¹ÝÇϱ⠶§¹®¿¡ ±Û·Î¹ú ¸®¼Ò½º¿Í Çù·ÂÇÒ ¼ö ¾ø´Ù. Á¤Àû ¸Þ¼Òµå È£ÃâÀº ¿À¹ö¶óÀÌµå µÉ ¼ö ¾ø±â ¶§¹®¿¡ È£ÃâÀº
ÀνºÅϽº ¸Þ¼Òµå°¡ ÇÒ ¼ö ÀÖ´Â ¹æ½ÄÀ¸·Î ¸®´ÙÀÌ·ºÆ® µÉ ¼ö ¾ø´Ù.
¸ðµç Deletable ¿¡¼ ¸Þ¼Òµå·Î Àü´ÞÇÒ ¼ö ÀÖ´Ù(Listing
4); ÇÏÁö¸¸ ½ÇÁ¦ ÀÌ Àå¼Ò¿¡¼ ´Ù¸¥ Ŭ·¡½º¸¦ ·ÎµùÇÒ ¶§ÀÇ ´ÜÁ¡Àº ÀÚ¹Ù ¾ð¾î¸¦ »ç¿ëÇÒ °æ¿ì Á¤Àû ¸Þ¼Òµå È£ÃâÀ»
mock ¸Þ¼Òµå È£Ãâ·Î ´ëüÇÒ ¼ö ¾ø´Ù.
refactoring
¿¹Á¦ ¸î¸î refactoringÀ¸·Î ¿©·¯ºÐÀÇ ¾ÖÇø®ÄÉÀÌ¼Ç Äڵ带 ½±°Ô Å×½ºÆ® ÇÒ ¼ö
ÀÖ´Â ¼Ö·ç¼ÇÀ¸·Î Á¶Á¤ÇÒ ¼ö ÀÖ´Ù. ÇÏÁö¸¸ Ç×»ó ±×·±°Í¸¸Àº ¾Æ´Ï´Ù. Å×½ºÆÃÀ» °¡´ÉÇÏ°Ô ÇÏ´Â RefactoringÀº
°á°ú ÄÚµåÀÇ À¯Áö¿Í ÀÌÇØ°¡ ´õ ¾î·Æ´Ù¸é ÀÌÄ¡¿¡ ¸ÂÁö ¾Ê´Â´Ù.
EJB ÄÚµå´Â ½¬¿î mock Å×½ºÆÃÀÌ °¡´ÉÇÑ »óÅ·Π¸®ÆÑÅ丵 ÇÏ´Â °ÍÀÌ ºÎºÐÀûÀ¸·Î °¡´ÉÇÏ´Ù. ¿¹¸¦ µé¾î,
mock Ä£ÈÀûÀÎ refactoringÀÇ ÇÑ À¯ÇüÀº ´ÙÀ½°ú °°Àº ÄÚµå À¯ÇüÀ» º¯È½ÃŲ´Ù:
//in EJBNumber1
public void doSomething(){
EJBNumber2 collaborator = lookupEJBNumber2();
//do something with collaborator
}
|
´ÙÀ½ À¯ÇüÀ¸·Î:
public void doSomething(EJBNumber2 collaborator){
//do something with collaborator
}
|
Ç¥ÁØ °´Ã¼ ÁöÇ⠽ýºÅÛ¿¡¼ refactoring ¿¹Á¦´Â È£ÃâÀÚ°¡ ÁÖ¾îÁø À¯´Ö¿¡ collaborator¸¦
Á¦°øÇÒ ¼ö ÀÖµµ·Ï ÇÔÀ¸·Î¼ À¯¿¬¼ºÀ» Çâ»ó½ÃŲ´Ù. ±×¿Í °°Àº refactoringÀº EJB ±â¹Ý ½Ã½ºÅÛ¿¡¼
°¡´ÉÇÏ´Ù. ÆÛÆ÷¸Õ½ºÀû Ãø¸é¿¡¼ ¿ø°Ý EJB Ŭ¶óÀ̾ðÆ®´Â °¡´ÉÇÏ¸é ¿ø°Ý ¸Þ¼Òµå È£ÃâÀ» ÇÇÇØ¾ß ÇÑ´Ù. µÎ ¹ø°
Á¢±Ù¹æ½ÄÀº Ŭ¶óÀ̾ðÆ®°¡ ¿ì¼± »ìÆ캸°í ±×·±´ÙÀ½ EJBNumber2 ÀÇ ÀνºÅϽº¸¦ ¸¸µé¾î¾ß
ÇÑ´Ù.
°Ô´Ù°¡, Ŭ¶óÀ̾ðÆ® ·¹À̾ EJBNumber2 ÀÇ Á¸Àç °°Àº ±¸Çö »ó¼¼¸¦ ¹Ýµå½Ã
¾ËÇÊ¿ä°¡ ¾ø´Â °æ¿ì Àß ¼³°èµÈ EJB ½Ã½ºÅÛÀº "°èÃþÀûÀÎ(layered)" Á¢±Ù¹æ½ÄÀ» ÃëÇÏ´Â °æÇâÀÌ ÀÖ´Ù.
EJB ÀνºÅϽº¸¦ ¾ò´Â À¯¸íÇÑ ¹æ½ÄÀº JNDI ÄÜÅؽºÆ®¿¡¼ ÆÑÅ丮¸¦ º¸°í³ ÈÄ ÆÑÅ丮»ó¿¡ »ý¼º ¸Þ¼Òµå¸¦ È£ÃâÇÏ´Â
°ÍÀÌ´Ù. ÀÌ·¯ÇÑ Àü·«Àº EJB ¾ÖÇø®ÄÉÀ̼ǿ¡ ¸¹Àº À¯¿¬¼ºÀ» °¡Á®´ÙÁØ´Ù. ¾ÖÇø®ÄÉÀÌ¼Ç Àü°³ÀÚµéÀº Àü°³ÇÒ ¶§,
¿ÏÀüÈ÷ ´Ù¸¥ EJBNumber2 ÀÇ ±¸ÇöÀ» ¹Ù²Ü ¼ö Àֱ⠶§¹®¿¡ ½Ã½ºÅÛ ÀÛµ¿Àº ½±°Ô
¸ÂÃçÁø´Ù. JNDI ¹ÙÀεùÀº ·±Å¸Àӽà ½±°Ô º¯°æµÇÁö ¾Ê´Â´Ù. µû¶ó¼ mock °´Ã¼ Å×½ºÅ͵éÀº
EJBNumber2 ¿ë mock¿¡¼ ¹Ù²Ù±â À§ÇØ ÀçÀü°³¸¦ ÇÒ °ÍÀÎÁö ¾Æ´Ï¸é Àüü Å×½ºÆÃ
¸ðµ¨À» Æ÷±âÇØ¾ß ÇÒ Áö¸¦ ¼±ÅÃÇØ¾ß ÇÑ´Ù.
´ÙÇàÈ÷, AspectJ°¡ ÀÖ´Ù.
À¯¿¬¼ºÀ» Ãß°¡ÇÑ
AspectJ AspectJ´Â ÄÜÅؽºÆ®¿¡ ¹Î°¨ÇÑ ÀÛµ¿ º¯°æÀ» Å×½ºÆ® ÄÉÀ̽º ±â¹ÝÀ¸·Î
Á¦°øÇÑ´Ù. mock °´Ã¼ÀÇ »ç¿ëÀ» ±ÝÇؾßÇÏ´Â »óȲ¿¡µµ ±×·¸´Ù. AspectJÀÇ join-point ¸ðµ¨Àº
aspect¶ó°í ÇÏ´Â ¸ðµâÀÌ ÇÁ·Î±×·¥ÀÇ ½ÇÇà ½ÃÁ¡À» È®ÀÎÇÒ ¼ö ÀÖµµ·Ï ÇÑ´Ù.
Aspect´Â pointcutsÀ» ÅëÇÑ ÇÁ·Î±×·¥ÀÇ Á¦¾î È帧¿¡¼ Æ÷ÀÎÆ®¸¦ È®ÀÎÇÑ´Ù.
pointcutÀº ÇÁ·Î±×·¥ ½ÇÇà ½Ã ÀÏ·ÃÀÇ Æ÷ÀÎÆ®¸¦ Áý¾î³»°í aspect°¡ ±×·¯ÇÑ joinpoint°ú °ü·ÃµÈ
°ÍÀ» ½ÇÇàÇÏ´Â ÄÚµå¶ó´Â °ÍÀ» Á¤ÀÇÇÒ ¼ö ÀÖµµ·Ï ÇÑ´Ù. °£´ÜÇÑ pointcutÀ» »ç¿ëÇÏ¿©, ¸ðµç ¸Å°³º¯¼ö°¡ ƯÁ¤
½ÅÈ£¿Í ¸ÅÄ¡µÇ´Â JNDI lookupÀ» ¼±ÅÃÇÒ ¼ö ÀÖ´Ù. ÇÏÁö¸¸ ¿ì¸®°¡ ¹«¾ùÀ» ÇϵçÁö °£¿¡ aspect´Â Å×½ºÆ®
Äڵ忡¼ ³ªÅ¸³ª´Â °Í¸¸ lookupÇÑ´Ù´Â °ÍÀ» È®ÀÎÇØ¾ß ÇÑ´Ù. À̸¦ À§ÇØ, cflow()
pointcutÀ» »ç¿ëÇÑ´Ù. cflow ´Â ÇÁ·Î±×·¥ ½ÇÇà¿¡¼ ´Ù¸¥ joinpointÀÇ
ÄÜÅؽºÆ® ³»¿¡¼ ¹ß»ýÇÏ´Â ¸ðµç Æ÷ÀÎÆ®¸¦ Áý¾î³½´Ù.
´ÙÀ½ ÄÚµå´Â ¿¹Á¦ ¾ÖÇø®ÄÉÀ̼ÇÀÌ cflow -based pointcutÀ» »ç¿ëÇÒ ¼ö
ÀÖµµ·Ï ¾î¶»°Ô º¯°æµÉ ¼ö ÀÖ´ÂÁö¸¦ º¸¿©ÁØ´Ù.
pointcut inTest() : execution(public void ClientBeanTest.test*());
/*then, later*/ cflow(inTest()) && //other conditions
|
ÀÌ ¶óÀεéÀº Å×½ºÆ® ÄÜÅؽºÆ®¸¦ Á¤ÀÇÇÑ °ÍÀÌ´Ù. ù ¹ø° ¶óÀÎÀº ¾Æ¹«°Íµµ ¸®ÅÏÇÏÁö ¾Ê°í °ø¿ë ¾×¼¼½º¸¦ °¡Áö°í
ÀÖÀ¸¸ç Å×½ºÆ® ¶ó´Â ´Ü¾î·Î ½ÃÀÛÇÏ´Â ClientBeanTest Ŭ·¡½ºÀÇ ¸ðµç ¸Þ¼Òµå
½ÇÇà¿¡ ´ëÇØ inTest() ¶ó´Â À̸§À» ºÎ¿©ÇÑ´Ù.
cflow(inTest()) ¼ö½ÄÀº ±×¿Í °°Àº ¸Þ¼Òµå ½ÇÇà°ú ¸®ÅÏ»çÀÌÀÇ ¸ðµç
joinpoint¸¦ Áý¾î³½´Ù. µû¶ó¼ cflow(inTest())
ClientBeanTest ½ÇÇà¿¡ ´ëÇÑ ¸Þ¼Òµå¸¦ Å×½ºÆ®ÇÏ°í ÀÖ´Â µ¿¾È" À̶ó´Â °ÍÀ»
ÀǹÌÇÑ´Ù.
»ùÇà ¾ÖÇø®ÄÉÀ̼ÇÀÇ Å×½ºÆ® ½´Æ®´Â µÎ °³ÀÇ ´Ù¸¥ ¼³Á¤À¸·Î ±¸ÇöµÉ ¼ö ÀÖ´Ù. °¢°¢ ´Ù¸¥ aspect¸¦
»ç¿ëÇÑ´Ù. ù ¹ø° ¼³Á¤Àº ½ÇÁ¦ CustomerManager ¸¦ mock °´Ã¼·Î ´ëüÇÑ´Ù.
µÎ ¹ø° ¼³Á¤Àº °´Ã¼µéÀ» ´ëüÇÏ´Â °ÍÀÌ ¾Æ´Ï¶ó Ŭ¶óÀ̾ðÆ® ºó¿¡ ÀÇÇÑ EJB ÄÄÆ÷³ÍÆ®¿¡ ÀÌ·ç¾îÁø È£ÃâÀ» ¼±ÅÃÀûÀ¸·Î
´ëüÇÑ´Ù. µÎ °æ¿ì ¸ðµÎ aspect´Â º¸¿©Áֱ⸦ °ü¸®ÇÏ¸é¼ Å¬¶óÀ̾ðÆ®°¡
CustomerManager ·Î ºÎÅÍ ¿¹°ßµÈ °á°ú¸¦ ¹ÞÀ» ¼ö ÀÖÀ½À» È®ÀÎÇÑ´Ù. ÀÌ·¯ÇÑ
°á°úµéÀ» üũÇÔÀ¸·Î¼ ClientBeanTest ´Â Ŭ¶óÀ̾ðÆ®°¡ EJB ÄÄÆ÷³ÍÆ®¸¦ Á¤È®È÷
»ç¿ëÇÏ°í ÀÖ´Ù´Â °ÍÀ» È®ÀÎÇÒ ¼ö ÀÖ´Ù.
EJB lookupÀ» ´ëüÇϱâ À§ÇØ
aspect »ç¿ëÇϱâ Listing 8ÀÇ Ã¹ ¹ø° ¼³Á¤Àº
ObjectReplacement ¶ó°í ÇÏ´Â aspect¸¦ ¿¹Á¦ ¾ÖÇø®ÄÉÀ̼ǿ¡ Àû¿ëÇÑ´Ù.
ÀÌ°ÍÀº Context.lookup(String) ¸Þ¼Òµå¿¡ ÀÌ·ç¾îÁø ¸ðµç È£ÃâÀÇ °á°ú¸¦
´ëüÇÔÀ¸·Î¼ ÀÛµ¿ÇÑ´Ù. Listing 8. ObjectReplacement
aspect
import javax.naming.Context;
public aspect ObjectReplacement{
/**
* Defines a set of test methods.
*/
pointcut inTest() : execution(public void ClientBeanTest.*());
/**
* Selects calls to Context.lookup occurring within test methods.
*/
pointcut jndiLookup(String name) :
cflow(inTest()) &&
call(Object Context.lookup(String)) &&
args(name);
/**
* This advice executes *instead of* Context.lookup
*/
Object around(String name) : jndiLookup(name){
if("java:comp/env/ejb/CustomerManager".equals(name)){
return new MockCustomerManagerHome();
}
else{
throw new Error("ClientBean should not lookup any EJBs " +
"except CustomerManager");
}
}
}
|
jndiLookup pointcut˼
Context.lookup() °ú °ü·ÃµÈ È£ÃâÀ» È®ÀÎÇϱâ À§ÇØ ÀÌÀü¿¡ ³íÀǵÈ
pointcutÀ» »ç¿ëÇÑ´Ù. jndiLookup pointcutÀ» Á¤ÀÇÇÑ ÈÄ¿¡,
lookup ´ë½Å ½ÇÇàÇÏ´Â Äڵ带 Á¤ÀÇÇÒ ¼ö ÀÖ´Ù.
"advice"¿¡
´ëÇÏ¿© AspectJ´Â joinpoint¿¡¼ ½ÇÇàµÇ´Â Äڵ带 ¼³¸íÇÏ´Â µ¥
advice ¶ó´Â ¿ë¾î¸¦ »ç¿ëÇÑ´Ù. ObjectReplacement
aspect´Â ÇϳªÀÇ advice (ÆĶõ»ö ºÎºÐ)¸¦ äÅÃÇÑ´Ù. advice´Â "JNDI LookupÀ» ¸¸³ª¸é,
¸Þ¼Òµå È£ÃâÀ» ÁøÇàÇÏ´Â ´ë½Å mock °´Ã¼¸¦ ¸®ÅÏÇ϶ó."°í ¸í·ÉÇÑ´Ù. ÀÏ´Ü mock °´Ã¼°¡ Ŭ¶óÀ̾ðÆ®·Î
¸®ÅϵǸé, aspectÀÇ ÀÛµ¿Àº ¿Ï¼ºµÇ°í mock °´Ã¼µéÀÌ Àΰè¹Þ´Â´Ù.
MockCustomerManagerHome ˼ create()
¸Þ¼Òµå·ÎÀÇ ¸ðµç È£Ãâ¿¡¼ custormer ¸Å´ÏÀúÀÇ mock ¹öÀüÀ» ¸®ÅÏÇÑ´Ù. mockÀº Á¤È®ÇÑ ½ÃÁ¡¿¡¼
ÇÁ·Î±×·¥¿¡ ÇÕ¹ýÀûÀ¸·Î µé¾î°¡±â À§ÇØ È¨ ÀÎÅÍÆäÀ̽º¸¦ ±¸ÇöÇØ¾ß Çϱ⠶§¹®¿¡ mock ¶ÇÇÑ
CustomerHome ÀÇ ¼öÆÛÀÎÅÍÆäÀ̽ºÀÎ EJBHome ÀÇ ¸Þ¼Òµå¸¦
±¸ÇöÇÑ´Ù. (Listing 9). Listing 9.
MockCustomerManagerHome
public class MockCustomerManagerHome implements CustomerManagerHome{
public CustomerManager create()
throws RemoteException, CreateException {
return new MockCustomerManager();
}
public javax.ejb.EJBMetaData getEJBMetaData() throws RemoteException {
throw new Error("Mock. Not implemented.");
}
//other super methods likewise
[...]
|
MockCustomerManager ´Â ´Ü¼øÇÏ´Ù. ¼öÆÛÀÎÅÍÆäÀ̽º ÀÛµ¿À» À§ÇØ ½ºÅÓ
¸Þ¼Òµå¸¦ Á¤ÀÇÇÏ°í ClientBean ÀÌ »ç¿ëÇÏ´Â ¸Þ¼Òµå¸¦ °£´ÜÇÏ°Ô ±¸ÇöÇÑ´Ù.
(Listing 10). Listing 10.
MockCustomerManager¿¡ ´ëÇÑ Mocked ¸Þ¼Òµå
public void register(String name) NameExistsException {
if( ! name.equals(ClientBeanTest.NEW_CUSTOMER)){
throw new NameExistsException(name + " already exists!");
}
}
public String[] getCustomersOver(int years) {
String[] customers = new String[55];
for(int i = 0; i < customers.length; i++){
customers[i] = "Customer Number " + i;
}
return customers;
}
|
¼º¼÷ÇÑ mock °´Ã¼µéÀº Å×½ºÆ® ÀÛµ¿À» ½±°Ô Ä¿½ºÅ͸¶ÀÌ¡ ÇÒ ¼ö ÀÖµµ·Ï ÇÏ´Â hook¸¦ Á¦°øÇÑ´Ù.
aspect¸¦ »ç¿ëÇÏ¿© EJB ÄÄÆ÷³ÍÆ®¿¡
È£Ãâ ´ëü½ÃÅ°±â EJB Àü°³ ´Ü°è¸¦ °Ç³Ê¶Ù´Â °ÍÀ¸·Î °³¹ßÀ» ½±°Ô ÇÒ ¼ö ÀÖÁö¸¸ ÃÖÁ¾
¸ñÇ¥¿¡ ±ÙÁ¢ÇÏ°Ô º¹Á¦µÈ ȯ°æ¿¡¼ Äڵ带 Å×½ºÆ® ÇÑ´Ù´Â ÀÌÁ¡ÀÌ ÀÖ´Ù. ¾ÖÇø®ÄÉÀ̼ÇÀ» ¿ÏÀüÈ÷ ÅëÇÕÇÏ°í Àü°³µÈ
¾ÖÇø®ÄÉÀ̼ǿ¡ ´ëÇØ Å×½ºÆ®¸¦ ½ÇÇàÇÏ¸é ¼³Á¤ ¹®Á¦¸¦ Á¶±â¿¡ ÇØ°áÇÒ ¼ö ÀÖ´Ù. ÀÌ°ÍÀº CactusÀÇ Ã¶ÇÐÀ¸·Î¼,
Cactus´Â ¿ÀÇ ¼Ò½ºÀÇ ¼¹öÃø Å×½ºÆà ÇÁ·¹ÀÓ¿÷ÀÌ´Ù.
¾Æ·¡ÀÇ ¿¹Á¦ ¾ÖÇø®ÄÉÀ̼ÇÀÇ ¼³Á¤Àº ¾ÖÇø®ÄÉÀÌ¼Ç ¼¹ö¿¡¼ Å×½ºÆ® ½ÇÇà¿¡ Cactus¸¦ »ç¿ëÇÑ´Ù. À̸¦ ÅëÇØ
ClientManager EJB°¡ Á¤È®È÷ ¼³Á¤µÇ¾ú°í ÄÁÅ×ÀÌ³Ê ³»ºÎÀÇ ´Ù¸¥ ÄÄÆ÷³ÍÆ®¿¡ ÀÇÇØ
¾×¼¼½º µÉ ¼ö ÀÖ´Ù´Â °ÍÀ» Å×½ºÆ®¸¦ ÅëÇØ È®ÀÎÇÒ ¼ö ÀÖ´Ù. AspectJ´Â ÀÌ·¯ÇÑ ½ºÅ¸ÀÏÀÇ ¹ÝÅëÇÕµÈ Å×½ºÆÃÀ»
º¸¿ÏÇÑ´Ù.
CallReplacement aspect´Â Å×½ºÆà ÄÁÅؽºÆ®ÀÇ Á¤ÀÇ·Î ½ÃÀÛÇÑ´Ù.
getCustomersOver() ¿Í register() ¸Þ¼Òµå¿¡
»óÀÀÇÏ´Â pointcutÀ» ÁöÁ¤ÇÑ´Ù. (Listing 11): Listing 11. CustomerManager¿¡ ´ëÇÑ Å×½ºÆ® È£Ãâ
¼±ÅÃÇϱâ
public aspect CallReplacement{
pointcut inTest() : execution(public void ClientBeanTest.test*());
pointcut callToRegister(String name) :
cflow(inTest()) &&
call(void CustomerManager.register(String)) &&
args(name);
pointcut callToGetCustomersOver() :
cflow(inTest()) &&
call(String[] CustomerManager.getCustomersOver(int));
//[...]
|
aspect´Â around advice¸¦ °¢°¢ÀÇ °ü·Ã ¸Þ¼Òµå È£Ãâ¿¡ ´ëÇØ Á¤ÀÇÇÑ´Ù.
getCustomersOver() ¶Ç´Â register() ·ÎÀÇ
È£ÃâÀÌ ClientBeanTest ³»¿¡¼ ¹ß»ýÇϸé, °ü·Ã advice°¡ ½ÇÇàµÈ´Ù.
(Listing 12): Listing 12. Advice°¡ Å×½ºÆ® ³»¿¡¼
¸Þ¼Òµå È£ÃâÀ» ´ëüÇÑ´Ù.
void around(String name) throws NameExistsException:
callToRegister(name) {
if(!name.equals(ClientBeanTest.NEW_CUSTOMER)){
throw new NameExistsException(name + " already exists!");
}
}
Object around() : callToGetCustomersOver() {
String[] customers = new String[55];
for(int i = 0; i < customers.length; i++){
customers[i] = "Customer Number " + i;
}
return customers;
}
|
µÎ ¹ø° ¼³Á¤Àº Å×½ºÆ® Äڵ带 ´Ù¼Ò ´Ü¼øÇÏ°Ô ÇÑ´Ù.
Pluggable Å×½ºÆ®
¼³Á¤ AspectJ´Â ÀÌ·¯ÇÑ µÎ °³ÀÇ ¼³Á¤µéÀ» Áï½Ã ¹Ù²Ü ¼ö ÀÖµµ·Ï ÇÑ´Ù.
aspect´Â ±×µé¿¡ ´ëÇØ ÀüÇô Áö½ÄÀÌ ¾ø´Â Ŭ·¡½º¿¡°Ô ¿µÇâÀ» ÁÙ ¼ö Àֱ⠶§¹®¿¡, ÄÄÆÄÀÏ ½Ã ´Ù¸¥
aspect¸¦ ÁöÁ¤ÇÏ¸é ·±Å¸ÀÓ ½Ã ½Ã½ºÅÛ¿¡ ¿ÏÀüÈ÷ ´Ù¸¥ ÀÛµ¿ °á°ú¸¦ °¡Á®¿Â´Ù. »ùÇà ¾ÖÇø®ÄÉÀ̼ÇÀº À̸¦ ÀÌ¿ëÇÑ
°ÍÀÌ´Ù: Listing 13. Ant´Â ´Ù¸¥ ¼³Á¤À» ¸ñÇ¥·ÎÇÏ°í
ÀÖ´Ù.
<target name="objectReplacement" description="...">
<antcall target="compileAndRunTests">
<param name="argfile"
value="${src}/ajtest/objectReplacement.lst"/>
</antcall>
</target>
[contents of objectReplacement.lst]
@base.lst;[A reference to files included in both configurations]
MockCustomerManagerHome.java
MockCustomerManager.java
ObjectReplacement.java.
<target name="callReplacement" description="...">
<antcall target="deployAndRunTests">
<param name="argfile"
value="${src}/ajtest/callReplacement.lst"/>
</antcall>
</target>
[contents of callReplacement.lst]
@base.lst
CallReplacement.java
RunOnServer.java
|
Ant ½ºÅ©¸³Æ®´Â argfile ¼Ó¼ºÀ» AspectJ ÄÄÆÄÀÏ·¯·Î º¸³½´Ù.
AspectJ ÄÄÆÄÀÏ·¯´Â ¾î¶² ¼Ò½º¸¦ ±¸Çö¿¡ Æ÷ÇÔÇÒ Áö¸¦ °áÁ¤Çϱâ À§ÇØ ÀÌ ÆÄÀÏÀ» »ç¿ëÇÑ´Ù.
argfile ÀÇ objectReplacement ¿¡¼
callReplacement ·Î º¯°æÇÔÀ¸·Î¼ ±¸ÇöÀº °£´ÜÇÑ ÀçÄÄÆÄÀÏ·Î Å×½ºÆà Àü·«À» º¯°æÇÒ
¼ö ÀÖ´Ù.
Cactus¿¡
Ç÷¯±×ÀÎÇϱâ
¿¹Á¦ ¾ÖÇø®ÄÉÀ̼ÇÀº Cactus¿Í ¹øµéµÈ´Ù. ÀÌ°ÍÀº ¾ÖÇø®ÄÉÀÌ¼Ç ¼¹ö ³»¿¡¼ Å×½ºÆ®¸¦ ½ÇÇàÇÏ´Â
µ¥ »ç¿ëµÈ´Ù. Cactus¸¦ »ç¿ëÇϱâ À§Çؼ, Å×½ºÆ® Ŭ·¡½º´Â
org.apache.cactus.ServletTestCase (ÀϹÝÀûÀÎ
junit.framework.TestCase ´ë½Å)À» È®ÀåÇؾßÇÑ´Ù. ÀÌ·¯ÇÑ
º£À̽º Ŭ·¡½º´Â ÀÚµ¿ÀûÀ¸·Î ¾ÖÇø®ÄÉÀÌ¼Ç ¼¹ö¿¡ Àü°³µÈ Å×½ºÆ®µé°ú Åë½ÅÇÑ´Ù.
"callReplacement " ¹öÀüÀÇ Å×½ºÆ®´Â ¼¹ö¸¦ ÇÊ¿ä·ÎÇÏÁö¸¸
"objectReplacement " ¹öÀüÀº ±×·¸Áö ¾Ê´Ù. AspectJÀÇ ´Ù¸¥
±â´ÉÀ» »ç¿ëÇÏ¿© Å×½ºÆ® Ŭ·¡½º ¼¹ö°¡ Àνĵǵµ·Ï ÇÑ´Ù.
ClientBeanTest ÀÇ ¼Ò½º ¹öÀüÀº
TestCase ¸¦ È®ÀåÇÑ´Ù. Å×½ºÆ®°¡ ¼¹öÃø¿¡¼ ½ÇÇàµÇ±æ ¿øÇϸé, ±¸Çö ¼³Á¤¿¡
´ÙÀ½ÀÇ aspect¸¦ Ãß°¡ÇÑ´Ù:
public aspect RunOnServer{
declare parents : ClientBeanTest extends ServletTestCase;
}
ÀÌ aspect¸¦ Ãß°¡ÇÔÀ¸·Î¼, ClientBeanTest ´Â
TestCase ´ë½Å ServletTestCase ¸¦
È®ÀåÇß´Ù.
|
°á·Ð Å×½ºÆ® °³¹ß
ºñ¿ëÀ» Àý°¨Çϱâ À§ÇØ ´ÜÀ§ Å×½ºÆ®´Â °í¸³µÈ »óÅ¿¡¼ ½ÇÇàÇØ¾ß ÇÑ´Ù. Mock °´Ã¼ Å×½ºÆÃÀº °¢°¢ÀÇ ´ÜÀ§¸¦ °í¸³È
ÇÑ´Ù. ÇÏÁö¸¸ °´Ã¼ ÁöÇâ ±â¼úÀº collaborate Äڵ带 ¼º°øÀûÀ¸·Î ´ëüÇÒ ¼ö ¾ø´Ù. AspectJÀÇ ±â´ÉÀº
ÀÌ·¯ÇÑ »óȲ¿¡¼ Äڵ带 ±ò²ûÇÏ°Ô ´ëüÇÑ´Ù.
Âü°íÀÚ·á
AspectJ
Unit-testing Åø & ±â¼ú
Ãß°¡ Âü°íÀÚ·á
|