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:
Code Block |
---|
|
@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.
Przykładowy test powyższej klasy miałby postać:
Code Block |
---|
|
@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:
Code Block |
---|
|
@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:
Code Block |
---|
|
@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()
{
// ...
}
} |
Warning |
---|
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ć lub zmockować. |