2012-03-14 10 views
10

miei problemi:Test per portlet plugin personalizzato: BeanLocatorException e Transaction roll-back per i test servizi

  1. posso testare con successo per il funzionamento dei servizi CRUD. Stavo facendo un inserto su @Before [setUp()] ed elimina gli stessi dati su @After [tearDown()] ma andando avanti avrei bisogno di supportare le Transazioni piuttosto che scrivere codice per inserire ed eliminare.
  2. io sono riuscito a prelevare singole registrazioni della mia entità, ma quando mi sparo una query di ricerca o cercare di prendere più di uno dei miei soggetti ottengo:

    com.liferay.portal.kernel.bean. BeanLocatorException: BeanLocator non è stato impostato per il contesto servlet MyCustom-portlet

ho seguito alcuni dei seguenti link per set-up Junit con Liferay:

mio Ambiente

  • Liferay 6.0.5 EE bundle con Tomcat

  • Eclipse Helios con Lifer ay IDE 1.4 utilizzando Junit4

  • Sto facendo funzionare i miei test con il comando "ant" in Eclipse per sé, ma non attraverso la digitazione Alt +Maiusc +X, T.

Sarebbe veramente utile se posso ottenere qualche idea di come fare per utilizzare le transazioni con JUnit (o almeno alcune idee quanto a come funziona in Liferay) e come risolvere il BeanLocatorException (o almeno perché dovrebbe essere gettato)

Qualsiasi aiuto sarà molto apprezzato.

+0

Qualcuno là fuori che sa qualcosa su come le transazioni lavorano in Liferay non necessariamente in casi di test, anche un piccolo suggerimento sarebbe utile o un URL o un ebook. Grazie –

risposta

4

che uso per quadro Mockito test JUnit e iniettare i servizi su PortalBeanLocatorUtil.setBeanLocator(...) -methode. Penso che sia chiaro come farlo con la configurazione della molla. Qui hai un esempio completo su come può essere usato. L'esempio è girato e va bene così, perché l'approccio è semplice e comprensibile.

package mst.unittest.example; 

import java.text.ParseException; 
import java.text.SimpleDateFormat; 
import java.util.Date; 

import org.junit.Before; 
import org.junit.Test; 

import com.liferay.portal.kernel.bean.BeanLocator; 
import com.liferay.portal.kernel.bean.PortalBeanLocatorUtil; 
import com.liferay.portal.kernel.exception.PortalException; 
import com.liferay.portal.kernel.exception.SystemException; 
import com.liferay.portal.model.User; 
import com.liferay.portal.service.UserLocalService; 
import com.liferay.portal.service.UserLocalServiceUtil; 

import static org.junit.Assert.*; 

import static org.mockito.Mockito.*; 

/** 
* @author [email protected] 
*/ 
public class MyUserUtilTest { 


    private BeanLocator mockBeanLocator; 

    @Before 
    public void init() { 
     //create mock for BeanLocator, BeanLocator is responsible for loading of Services 
     mockBeanLocator = mock(BeanLocator.class); 
     //... and insert it in Liferay loading infrastructure (instead of Spring configuration) 
     PortalBeanLocatorUtil.setBeanLocator(mockBeanLocator); 
    } 

    @Test 
    public void testIsUserFullAge() throws PortalException, SystemException, ParseException { 
     //setup 
     SimpleDateFormat format = new SimpleDateFormat("yyyy_MM_dd"); 
     Date D2000_01_01 = format.parse("2000_01_01"); 
     Date D1990_06_30 = format.parse("1990_06_30"); 
     UserLocalService mockUserLocalService = mock(UserLocalService.class); 
     User mockUserThatIsFullAge = mock(User.class); 
     when(mockUserThatIsFullAge.getBirthday()).thenReturn(D1990_06_30); 
     User mockUserThatIsNotFullAge = mock(User.class); 
     when(mockUserThatIsNotFullAge.getBirthday()).thenReturn(D2000_01_01); 
     //overwrite getUser(...) methode so that wir get mock user-object with mocked behavior 
     when(mockUserLocalService.getUser(1234567)).thenReturn(mockUserThatIsFullAge); 
     when(mockUserLocalService.getUser(7654321)).thenReturn(mockUserThatIsNotFullAge); 

     //load our mock-object instead of default UserLocalService 
     when(mockBeanLocator.locate("com.liferay.portal.service.UserLocalService")).thenReturn(mockUserLocalService); 


     //run 
     User userFullAge = UserLocalServiceUtil.getUser(1234567); 
     boolean fullAge = MyUserUtil.isUserFullAge(userFullAge); 

     //verify 
     assertTrue(fullAge); 

     //run 
     User userNotFullAge = UserLocalServiceUtil.getUser(7654321); 
     boolean notfullAge = MyUserUtil.isUserFullAge(userNotFullAge); 

     //verify 
     assertFalse(notfullAge); 
    } 

} 

class MyUserUtil { 

    public static boolean isUserFullAge(User user) throws PortalException, SystemException { 
     Date birthday = user.getBirthday(); 
     long years = (System.currentTimeMillis() - birthday.getTime())/((long)365*24*60*60*1000); 
     return years > 18; 
    } 

} 

È possibile utilizzare questo approccio anche senza quadro Mockito, quindi è necessario creare le mock-classi come MockBeanLocator manualmente.

Approccio con PowerMock

Con PowerMock si può abdicare BeanLocator perché PowerMock permette di sovrascrivere i metodi statici. Ecco lo stesso esempio con PowerMock:

package mst.unittest.example; 

import java.text.ParseException; 
import java.text.SimpleDateFormat; 
import java.util.Date; 

import org.junit.Test; 
import org.junit.runner.RunWith; 
import org.powermock.api.mockito.PowerMockito; 
import org.powermock.core.classloader.annotations.PrepareForTest; 
import org.powermock.modules.junit4.PowerMockRunner; 

import com.liferay.portal.kernel.exception.PortalException; 
import com.liferay.portal.kernel.exception.SystemException; 
import com.liferay.portal.model.User; 
import com.liferay.portal.service.UserLocalServiceUtil; 

import static org.junit.Assert.*; 

import static org.mockito.Mockito.*; 

/** 
* @author Mark Stein 
* 
*/ 

@RunWith(PowerMockRunner.class) 
@PrepareForTest(UserLocalServiceUtil.class) 
public class LiferayAndPowerMockTest { 

    @Test 
    public void testIsUserFullAge() throws PortalException, SystemException, ParseException { 
     //setup 
     SimpleDateFormat format = new SimpleDateFormat("yyyy_MM_dd"); 
     Date D2000_01_01 = format.parse("2000_01_01"); 
     Date D1990_06_30 = format.parse("1990_06_30"); 
     User mockUserThatIsFullAge = mock(User.class); 
     when(mockUserThatIsFullAge.getBirthday()).thenReturn(D1990_06_30); 
     User mockUserThatIsNotFullAge = mock(User.class); 
     when(mockUserThatIsNotFullAge.getBirthday()).thenReturn(D2000_01_01); 

     //overwrite getUser(...) by UserLocalServiceUtil methode so that wir get mock user-object with mocked behavior 
     PowerMockito.mockStatic(UserLocalServiceUtil.class); 
     when(UserLocalServiceUtil.getUser(1234567)).thenReturn(mockUserThatIsFullAge); 
     when(UserLocalServiceUtil.getUser(7654321)).thenReturn(mockUserThatIsNotFullAge); 

     //run 
     boolean fullAge = MySecUserUtil.isUserFullAge(1234567); 

     //verify 
     assertTrue(fullAge); 

     //run 

     boolean notfullAge = MySecUserUtil.isUserFullAge(7654321); 

     //verify 
     assertFalse(notfullAge); 
    } 

} 

class MySecUserUtil { 

    public static boolean isUserFullAge(long userId) throws PortalException, SystemException { 
     User user = UserLocalServiceUtil.getUser(userId); 
     Date birthday = user.getBirthday(); 
     long years = (System.currentTimeMillis() - birthday.getTime())/((long)365*24*60*60*1000); 
     return years > 18; 
    } 

} 

Qui hai trovato PowerMock 1.4.12 con Mockito e JUnit incluse le dipendenze http://code.google.com/p/powermock/downloads/detail?name=powermock-mockito-junit-1.4.12.zip&can=2&q=

+0

Grazie mille! Questo mi dà luce su questa cosa di test delle unità. Così funzionerà se uso la mia classe 'com.prakash.MyLocalService' invece di' com.liferay.portal.service.UserLocalService'? Proverò questo e ti faccio sapere. Grazie ancora! –

+0

Sì, lo puoi fare anche per i propri servizi, ma devi usare 'PortletBeanLocatorUtil' invece di' PortalBeanLocatorUtil', o prendere PowerMock-addizione per Mockito e simulare direttamente la classe 'com.prakash.MyLocalServiceUtil' – Mark

+0

Great! Grazie! Sarebbe bello poter includere queste informazioni anche nella tua risposta. Grazie Marco. –

2

Speculazione: hai davvero bisogno di testare la transazione? O solo la logica di business attorno all'accesso db? Perché se è così, si potrebbe provare a scrivere il test di unità con EasyMock (o simile), evitando l'accesso alla banca dati ancora testare la funzionalità

+0

Ci proveremo. Grazie per il suggerimento. Ho bisogno di testare le transazioni, ma suppongo che possa aspettare :-). Hai qualche idea di usarlo con liferay? –

+0

Stai utilizzando ServiceBuilder per le tue entità? Se è così, penso (non sicuro al 100%) che non sarai in grado di farlo. La mia esperienza con Liferay mi dice che ogni chiamata che fai ad un servizio è una transazione. Anche Liferay funziona così sul suo backend. Se fossi in te, proverei a impostare il mio contesto Spring (e non quello di Liferay), configurare Hibernate (puoi farne uso come sorgente dati di liferay) e andare da lì. Progetta il tuo servizio con un aspetto @Transactional e verifica le tue transazioni – gcesarmza

+0

Sto usando il Service Builder di liferay. "La mia esperienza con Liferay mi dice che ogni chiamata che fai ad un servizio è una transazione" - chiama attraverso la classe ServiceUtil, poi Sì. Ma possiamo chiamare più metodi di servizio attraverso le istanze di * servizio a nostra disposizione. Stavo pensando che Service Builder utilizza Spring Context e ibernazione. –