Komponenty najlepiej testować z frameworkami TestNG oraz Mockito, gdyż istnieją one już w projekcie systemu. TestNG służy do tworzenia kolejnych testów jednostkowych, sprawdzania warunków, inicjalizacji testów, łapania pożądanych wyjątków itp. Mockito służy natomiast do tworzenia implementacji i wstrzykiwania obiektów, które są niezbędne do przetestowania niektórych funkcjonalności (np. gdy komponent używa systemowych serwisów ProcessService, UserService itp.).
Przykładowy datachooser korzystający z serwisu UserFinder:
@DataChooser public class FindingUserDataChooser { @Autowired private UserFinder userFinder; @Define public void definition( DataChooserDefinitionBuilder builder ) { // @formatter:off builder .id( "finding-user-datachooser" ) .name( "finding-user-datachooser-name" ) .description( "finding-user-datachooser-desc" ) .category( Categories.CUSTOM ) .mapping() .id( "fullname-mapping" ) .name( "fullname-mapping-name" ) .description( "fullname-mapping-desc" ) .create(); // @formatter:on } public void data( ComponentQueryData queryData, DataChooserResult result ) { String username = queryData.getQuery(); DetachedCriteria criteria = DetachedCriteria.forClass( User.class ); criteria.add( Restrictions.like( "userName", username ) ); List<User> users = userFinder.findByCriteria( criteria ); // itd... } }
Do tak stworzonego komponentu zostanie wstrzyknięty przez adnotację @Autowired systemowy serwis UserFinder.
Aby używać systemowe serwisy we wtyczkach, należy zaimportować je również w deskryptorze wtyczki (Import i udostępnianie serwisów).
Przykładowy test powyższej klasy miałby postać:
@Test public class FindingUserDataChooserTest { @InjectMocks FindingUserDataChooser component = new FindingUserDataChooser(); @Mock UserFinder userFinder; @Before private void init() { MockitoAnnotations.initMocks( this ); when( userFinder.findByCriteria( any( DetachedCriteria.class ) ) ).thenReturn( getSampleUserList() ); } private List<User> getSampleUserList() { User user1 = new User( "user1", "password" ); User user2 = new User( "user2", "password" ); return Lists.newArrayList( user1, user2 ); } @Test private void componentTest() { // ... } }
Serwis UserFinder został zmockowany przez adnotację @Mock. Statyczne metody when i thenReturn określają zachowanie się serwisu UserFinder dla konkretnych wywołań. Należy pamiętać, że nie jest to prawdziwy systemowy serwis, a jedynie tymczasowa implementacja na czas wykonywania testów. Adnotacja @InjectMocks mówi o tym, iż do stworzonego obiektu komponentu (FindingUserDataChooser) Mockito będzie próbował wstrzyknąć implementacje do jego pól (w tym przypadku wstrzyknie UserFindera).
Systemowe serwisy można również wstrzykiwać w komponentach przez stworzenie oznaczonego adnotacją @Autowired konstruktora posiadającego w parametrach kolejne serwisy. Przykładowy komponent:
@DataChooser public class FindingUserDataChooser { private UserFinder userFinder; @Autowired public FindingUserDataChooser( UserFinder userFinder ) { this.userFinder = userFinder; } @Define public void definition( DataChooserDefinitionBuilder builder ) { // @formatter:off builder .id( "finding-user-datachooser" ) .name( "finding-user-datachooser-name" ) .description( "finding-user-datachooser-desc" ) .category( Categories.CUSTOM ) .mapping() .id( "fullname-mapping" ) .name( "fullname-mapping-name" ) .description( "fullname-mapping-desc" ) .create(); // @formatter:on } public void data( ComponentQueryData queryData, DataChooserResult result ) { String username = queryData.getQuery(); DetachedCriteria criteria = DetachedCriteria.forClass( User.class ); criteria.add( Restrictions.like( "userName", username ) ); List<User> users = userFinder.findByCriteria( criteria ); // itd. } }
W takim przypadku również serwis UserFinder zostanie poprawnie zaciągnięty przez komponent. Komponent można przetestować w poniższy sposób:
@Test public class FindingUserDataChooserTest { FindingUserDataChooser component; @Mock UserFinder userFinder; @Before private void init() { MockitoAnnotations.initMocks( this ); when( userFinder.findByCriteria( any( DetachedCriteria.class ) ) ).thenReturn( getSampleUserList() ); component = new FindingUserDataChooser( userFinder ); } private List<User> getSampleUserList() { User user1 = new User( "user1", "password" ); User user2 = new User( "user2", "password" ); return Lists.newArrayList( user1, user2 ); } @Test private void componentTest() { // ... } }
Pamiętać należy również, że do wywołania komponentów należy stworzyć specyficzne dla rodzaju komponentu obiekty. Przykładowo dla powyższego DataChoosera można zauważyć, iż metoda data przyjmuje obiekty ComponentQueryData oraz DataChooserResult, które w testach należy własnoręcznie stworzyć.