IBM Korea Skip to main content
       IBM Ȩ    |  Á¦Ç° & ¼­ºñ½º  |  °í°´Áö¿ø & ´Ù¿î·Îµå  |  È¸¿ø°¡ÀÔ  

AspectJ¿Í mock °´Ã¼¸¦ ÀÌ¿ëÇÑ À¯¿¬ÇÑ Å×½ºÆÃ
Å×½ºÆ® Àü¿ë ÀÛµ¿À¸·Î ´ÜÀ§ Å×½ºÆ® Çâ»ó½ÃÅ°±â

Level: Intermediate

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 Åø & ±â¼ú

Ãß°¡ Âü°íÀÚ·á

¸ñ Â÷:
´ÜÀ§ Å×½ºÆ® ¿¹Á¦
µ¥ÀÌÅÍ ÀÇÁ¸ Å×½ºÆ®ÀÇ ¹®Á¦Á¡
Mock °´Ã¼ Å×½ºÆÃ
mock °´Ã¼ÀÇ ÇÑ°è
À¯¿¬¼ºÀ» Ãß°¡ÇÑ AspectJ
Pluggable Å×½ºÆ® ¼³Á¤
°á·Ð
Âü°í ÀÚ·á
ÇÊÀÚ ¼Ò°³
±â»ç¿¡ ´ëÇÑ Æò°¡
°ü·Ã dW ¸µÅ©:
Improve modularity with aspect-oriented programming
Automating the build and test process
Incremental development with Ant and JUnit
XP distilled
Subscribe to the developerWorks newsletter
US ¿ø¹® Àбâ
Also in the Java zone:
Tutorials
Tools and products
Code and components
Articles
ÇÊÀÚ¼Ò°³
Nicholas Lesiecki´Â dot.com ºÕ ½Ã´ë¿¡ ÀÚ¹Ù ÇÁ·Î±×·¡¹ÖÀÇ ¼¼°è¿¡ ÀÔ¹®ÇÏ¿´°í ±× ÀÌÈÄ XP¿Í °°Àº ¹ÎøÇÑ ÇÁ·Î¼¼½º¿¡¼­ ¿ÀÇ ¼Ò½º ±¸Ãà ¹× Å×½ºÆà ÅøÀ» ÀÀ¿ëÇϱâ À§ÇÑ ¹æ¹ýÀ» ´ãÀº ¸Å´º¾óÀÎ Java Tools for Extreme ProgrammingÀÇ ÃâÆÇ°ú ÇÔ²² XP¿Í ÀÚ¹Ù Ä¿¹Â´ÏƼ¿¡¼­ Ź¿ùÇÑ ¸í¼ºÀ» ½×¾Æ ¿Ô´Ù. ±×´Â ÇöÀç eBlox, Inc.ÀÇ °í±Þ ¿Â¶óÀÎ Ä«Å»·Î±× ½Ã½ºÅÛÀÎ storeBloxÀÇ °³¹ßÀ» À̲ø°í ÀÖ´Ù. ±×´Â Tucson JUG¿¡¼­ ºó¹øÇÏ°Ô ¿¬¼³ÇÒ »Ó ¾Æ´Ï¶ó JakartaÀÇ Cactus ÇÁ·ÎÁ§Æ® (¼­¹öÃø ´ÜÀ§ Å×½ºÆ® ÇÁ·¹ÀÓ¿öÅ©)¿¡ Àû±ØÀûÀ¸·Î Âü¿©ÇÏ°í ÀÖ´Ù.
ÀÌ ±â»ç¿¡ ´ëÇÏ¿© ¾î¶»°Ô »ý°¢ÇϽʴϱî?

Á¤¸» ÁÁ´Ù (5) ÁÁ´Ù (4) ±×Àú±×·¸´Ù (3) ¼öÁ¤º¸¿ÏÀÌ ÇÊ¿äÇÏ´Ù(2) ÇüÆí¾ø´Ù (1)

  È¸»ç¼Ò°³  |  °³ÀÎÁ¤º¸ º¸È£Á¤Ã¥  |  ¹ý·ü  |  ¹®ÀÇ