Seitenhistorie
...
Codeblock | ||||
---|---|---|---|---|
| ||||
[...] // siehe oben @BeforeClass(dependsOnMethods={"springTestContextPrepareTestInstance"}) public void setupParamValidation(){ // Test class setup code with autowired classes goes here } @AfterTest(alwaysRun=true) public void afterTest() { reset(masterDataFacade); } |
Ein Beispiel für Boilerplate Code, den man recht oft benötigt. Die Method setupParamValidation
hat Platz vor Code, der nach der Spring Context Erzeugung und vor allen Tests ausgeführt werden soll. Wichtig ist hier nicht der Methodenname, sondern die Annotierung. Diese Methode hat für den TestNG ungefähr die Funktion, die eine mit @PostConstruct
annotierte Methode für Spring Beans hat.
Mock Objekte muss man nach jeden Tests auf den Ausgangszustand zurücksetzen, damit Problem, die sich in einem Test ergeben, nicht in den danach ausgeführten Test propagieren. In TestNG gelingt dies mit der Annotation @AfterTest(alwaysRun=true)
. Typischerweise wird das reset
von Mockito für die Mock Objekte aufgerufen, die mittels Spring injiziert wurden.
Typischer Test
Codeblock | ||||
---|---|---|---|---|
| ||||
[...] // siehe oben
@Test
public void testGetSubNodesForRootSubnodes1() throws CommonBusinessException {
// u.U. wegen afterTest Method nicht notwendig
reset(masterDataFacade);
// prepare input data
final MasterDataVO<Long> sub1 = dataFactory.getBO_Fahrzeugbaum(null, "sub1");
final Long sub1Id = sub1.getPrimaryKey();
final PdmcaeTreeNode sub1Node = dataFactory.asPdmcaeTreeNode(sub1);
final MasterDataVO<Long> sub2 = dataFactory.getBO_Fahrzeugbaum(null, "sub2");
final Long sub2Id = sub2.getPrimaryKey();
final PdmcaeTreeNode sub2Node = dataFactory.asPdmcaeTreeNode(sub2);
final MasterDataVO<Long> subsub = dataFactory.getBO_Fahrzeugbaum(sub2, "subOfSub2");
final Long subsubId = subsub.getPrimaryKey();
final PdmcaeTreeNode subsubNode = dataFactory.asPdmcaeTreeNode(subsub);
final PdmcaeRootTreeNode root = PdmcaeRootTreeNode.getInstance();
root.setSearchResultSubnodeIds((Set) dataFactory.set(sub1Id, null, sub2Id));
// prepare mocks
// for getSubnodesByIds
when(masterDataFacade.getMasterData(eq(BO_Fahrzeugbaum), (CollectableSearchCondition) any(), eq(true))).thenReturn(
(TruncatableCollection) TruncatableCollectionDecorator.createUntruncated(dataFactory.list(sub1, sub2)));
// Method to test
final List<TreeNode> result = dut.getSubNodes(root);
LOG.info("getSubNodesForRootSubnodes1: result is " + result);
// return value verification
assertEquals(result.size(), 2);
assertTrue(result.contains(sub1Node));
assertTrue(result.contains(sub2Node));
assertFalse(result.contains(subsubNode));
// mock verification
verify(masterDataFacade).getMasterData(eq(BO_Fahrzeugbaum), (CollectableSearchCondition) any(), eq(true));
verifyNoMoreInteractions(masterDataFacade);
} |
Der eigentliche Unit Test gliedert sich in folgende Teile:
@Test
Annotierungreset
Mock Objekte (optional)- Aufbau der/des Input Value Object(s)
- Definition, was von den Mock Objekten zur Laufzeit erwartet wird (d.h. Definition der erwarteten Methodenaufrufe und deren Rückgabewerte)
- Aufruf der zu testenden Methode
- Verifikation des Ergebnisses (d.h. des Rückgabewertes und der Änderungen an den Input Value Objects)
- Verifikation der Mock Objekte
An diesem einfachen Testfall kann man bereits erkennen, das er Aufruf der zu testenden Methode nur ein ganz kleiner Teil des Unit Testes ist. Den größten Teil eines Tests nimmt meist die Behandlung der Mock Objekte in Anspruch. Es ist daher notwendig, sich mit dem verwendeten Mock Framework gut auszukennen.