3. Mock-Deklaration als Local Variable
?
Ganz einfach !?
Hier ein Versuch, eine lokale Variable einer Test-Methode als Mock zu deklarieren:
[java highlight=“6″]
public final class MyTest
{
@Test( dataProvider = "getTestData" )
public void login_should_accept( final IUser user, final IPassword password )
{
@Mocked
final IDatabase mockedDatabase;
// …
final boolean loginStatus = mockedDatabase.login( user, password );
// and so on …
}
}
[/java]
In Zeile 6 ist die Deklaration des Mocks angegeben, in Zeile 4 die Parameter aus dem @DataProvider
.
Leider funktioniert dies (derzeit) nicht in JMockit. Bei dem Versuch einer solchen Deklaration erhält man eine Fehlermeldung (in der Eclipse-IDE [4]: „The annotation @Mocked is disallowed for this location“).
Was tun?
Es gibt einen ganz unspektakulären Workaround:
man kombiniert einfach die zuvor beschriebene Variante 1.b. „Mock-Deklaration imExpectations
-Block“ mit der Deklaration einer „Local Mock Variable“ !
D.h. der Mock wird als Local Field
eines Expectations
-Blocks deklariert, dann aus diesem herausgereicht und an die lokale – dadurch nun den erzeugten Mock beinhaltenden(!) – Variable zugewiesen (Zeilen 7-11):
[java highlight=“7,8-11″]
public final class MyTest
{
@Test( dataProvider = "getTestData" )
public void login_should_accept( final IUser user, final IPassword password )
{
// @Mocked … disallowed here
final IDatabase mockedDatabase = new Expectations()
{
@Mocked
IDatabase mockedDatabase;
}.mockedDatabase;
// …
final boolean loginStatus = mockedDatabase.login( user, password );
// and so on …
}
}
[/java]
Der Expections
-Block wird hier etwas zweckentfremdet:
er wird nur zur Deklaration des Mocks genutzt, die eigentlichen Expectations
, d.h. der Initialisierungsblock { ... }
, sind nicht vorhanden.
Etwas „schöner“ im Sinne von „Clean Code„, z.B. „Separation of Concerns (SoC)„, könnte man dies noch wie folgt umstellen (Zeilen 6 und 14-21):
[java highlight=“6,14-21“]
public final class MyTest
{
@Test( dataProvider = "getTestData" )
public void login_should_accept( IUser user, IPassword password )
{
IDatabase mockedDatabase = createDatabaseMock();
// …
boolean loginStatus = mockedDatabase.login( user, password );
// and so on …
}
private IDatabase createDatabaseMock()
{
return new Expectations()
{
@Mocked
IDatabase mockedDatabase;
}.mockedDatabase;
}
}
[/java]
Zusammenfassung
Möglicherweise etwas „tricky“ – aber solange JMockit die direkte Deklaration von lokalen, gemockten Variablen (Stichwort „Test Isolation“) nicht zulässt und man gleichzeitig den Komfort der TestNG-DataProvider
nutzen möchte, erscheint dies – hoffentlich nicht nur für mich – eine gangbare Lösung.
Habt Ihr weitere Anregungen ?
Dann her damit …
CU
@ Boeffi .net aktualisiert am 24.05.2018
[1] → JMockit 0.999.10 – https://code.google.com/p/jmockit
[2] → FEST Fluent Assertions – https://fest.easytesting.org/
[3] → TestNG 6.2.0 – https://testng.org
[4] → Eclipse Indigo SR1 – https://www.eclipse.org