J'ai la classe suivante:
public class MyClass {
private Apple apple;
public void myMethod() {
Apple = AppleFactory.createInstance(someStringVariable);
....
....
....
}
}
Et la classe de test:
@RunWith(MockitoJUnitRunner.class)
public class MyClassTest {
@InjectMocks
MyClass myClass;
@Test
public void myMethod(){
...
...
...
}
}
Comment puis-je injecter une instance Apple comme maquette dans MyClass?
Vous avez 3 possibilités pour résoudre ceci:
Fabrique abstraite : Au lieu d’utiliser une méthode statique, utilisez une classe d’usine concrète:
public abstract class AppleFactory {
public Apple createInstance(final String str);
}
public class AppleFactoryImpl implements AppleFactory {
public Apple createInstance(final String str) { // Implementation }
}
Dans votre classe de test, moquez-vous de l'usine:
@RunWith(MockitoJUnitRunner.class)
public class MyClassTest {
@Mock
private AppleFactory appleFactoryMock;
@Mock
private Apple appleMock;
@InjectMocks
MyClass myClass;
@Before
public void setup() {
when(appleFactoryMock.createInstance(Matchers.anyString()).thenReturn(appleMock);
}
@Test
public void myMethod(){
...
...
...
}
}
PowerMock : Utilisez PowerMock pour créer une maquette d'une méthode statique. Regardez ma réponse à une question pertinente pour voir comment cela se fait.
Classe testable : Créez la création Apple
encapsulée dans une méthode protected
et créez une classe de test qui la redéfinit:
public class MyClass {
private Apple apple;
public void myMethod() {
Apple = createApple();
....
....
....
}
protected Apple createApple() {
return AppleFactory.createInstance(someStringVariable);
}
}
@RunWith(MockitoJUnitRunner.class)
public class MyClassTest {
@Mock
private Apple appleMock;
@InjectMocks
MyClass myClass;
@Test
public void myMethod(){
...
...
...
}
private class TestableMyClass extends MyClass {
@Override
public void createApple() {
return appleMock;
}
}
}
Bien sûr, dans votre classe de test, vous devriez tester TestableMyClass
et non MyClass
.
Je vais vous dire mon opinion sur chacune des méthodes:
La méthode de fabrique abstraite est la meilleure - C’est une conception claire qui cache les détails de la mise en oeuvre
La classe testable - est la deuxième option qui nécessite des modifications minimales
PowerMock
est ma moins préférée - au lieu de chercher un meilleur design, vous ignorez et cachez votre problème. Mais c'est toujours une option valable.En ce qui concerne la première réponse de Avi & Ev0oD. Les classes abstraites peuvent uniquement être étendues et non implémentées.
public abstract class AppleFactory {
public abstract Apple createInstance(final String str);
}
public class AppleFactoryImpl extends AppleFactory {
public Apple createInstance(final String str) { // Implementation }
}
En plus de la solution proposée par Avi, vous pouvez choisir une quatrième possibilité:
Injecter en usine: Ceci est, pour moi, la meilleure option lorsque vous avez déjà du code à refacrot. Avec cette solution, vous n'avez pas besoin de changer le code de réduction, mais seulement la classe d'usine et le test.
public class AppleFactory
{
private static Apple _injectedApple;
public static createInstance(String str)
{
if (_injectedApple != null)
{
var currentApple = _injectedApple;
_injectedApple = null;
return currentApple;
}
//standard implementation
}
public static setInjectedApple(Apple apple)
{
_injectedApple = Apple;
}
}
Maintenant, vous pouvez utiliser votre usine statique simplement:
@RunWith(MockitoJUnitRunner.class)
public class MyClassTest {
@Mock
private Apple appleMock;
@InjectMocks
MyClass myClass;
@Before
public void setup() {
AppleFactory.setInjectedApple(appleMock);
}
@Test
public void myMethod(){
...
...
...
}
}