Sonntag, 9. August 2020
Seite wählen

"Local Mock Variables" — Ein dritter eleganter Weg in JMockit?

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 im Expectations-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 …

about "Boeffi" ...CU
@ Boeffi  .net     aktualisiert am 24.05.2018

 

[1] → JMockit 0.999.10 – http://code.google.com/p/jmockit
[2] → FEST Fluent Assertions – http://fest.easytesting.org/
[3] → TestNG 6.2.0 – http://testng.org
[4] → Eclipse Indigo SR1 – http://www.eclipse.org

Medien- / Artikelbilder-Nachweis: Danke an und © siehe » 
aigle_dore