2014-02-19 3 views
8

Ich habe die folgende Klasse:Inject Mocks für von Factory-Klassen erstellt Objekte

public class MyClass {   
    private Apple apple; 

    public void myMethod() { 
     apple = AppleFactory.createInstance(someStringVariable); 
     .... 
     .... 
     .... 
    } 
} 

und die Testklasse:

@RunWith(MockitoJUnitRunner.class) 
public class MyClassTest { 

     @InjectMocks 
     MyClass myClass; 

     @Test 
     public void myMethod(){ 
     ... 
     ... 
     ... 
     } 
    } 

Wie könnte ich eine Apple-Instanz als Mock in MyClass injizieren?

Antwort

16

Sie haben 3 Möglichkeiten, diese zu lösen:

Abstrakte Fabrik: Anstelle einer statischen Methode der Verwendung einer Betonfabrik-Klasse verwenden:

public abstract class AppleFactory { 
    public Apple createInstance(final String str); 
} 

public class AppleFactoryImpl implements AppleFactory { 
    public Apple createInstance(final String str) { // Implementation } 
} 

In Ihrer Testklasse, verspotten die Fabrik:

@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: Verwenden Sie PowerMock ein Modell eines sta erstellen tic-Methode. Schauen Sie sich my answer to a relevant question an, um zu sehen, wie es gemacht wird.

Prüfbar Klasse: Machen Sie die Apple in einem protected Verfahren gewickelte Erstellung und eine Testklasse erstellen, die es außer Kraft setzt:

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; 
     } 
    } 
} 

Natürlich in Ihrer Testklasse Sie TestableMyClass und nicht MyClass testen.

Ich werde Ihnen meine Meinung sagen, auf jedem der Methoden:

  1. Die abstrakte Factory-Methode ist die beste - Dies ist ein klares Design, das die Details der Implementierung versteckt

  2. Die testbare Klasse - Ist die zweite Option, die minimale Änderungen erfordert

  3. Die PowerMock Option ist meine am wenigsten - Statt für ein besseres Design zu gehen, ignorieren Sie und verstecken Ihr Problem. Aber das ist immer noch eine gültige Option.
+0

Ehrfürchtig, danke. Ich muss Mockito in meiner Situation verwenden, also werde ich mit den Optionen von Abstract Factory oder TestableClass gehen. –

+1

@saravana_pc - Ich habe mein Ranking zu den Problemen hinzugefügt. Trotzdem können Sie 'Mockito' mit Power Mock verwenden. Anstatt "@ Mock" und "@ InjectMock" zu verwenden, können Sie ihre äquivalenten Methoden verwenden (und damit können Sie die @RunWith (MockitoJUnitRunner.class) -Deklaration loswerden) – Avi

+1

wenn Sie das abstrakte Fabrikmuster implementieren, wird keine Schnittstelle verwendet passender sein? –

0

Neben der Lösung von Avi vorgeschlagen, können Sie eine vierte Möglichkeit wählen:

Inject in Factory: Dies ist für mich die beste Option, wenn Sie bereits Code müssen refacrot. Mit dieser Lösung müssen Sie den Programmiercode nicht ändern, sondern nur die Werksklasse und den 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; 
    } 
} 

Jetzt können Sie Ihre statische Factory verwenden Sie einfach:

@RunWith(MockitoJUnitRunner.class) 
public class MyClassTest { 

    @Mock 
    private Apple appleMock; 

    @InjectMocks 
    MyClass myClass; 

    @Before 
    public void setup() { 
     AppleFactory.setInjectedApple(appleMock); 
    } 

    @Test 
    public void myMethod(){ 
    ... 
    ... 
    ... 
    } 
} 
+0

Und wie testen Sie AppleFactory dann? – Ciberman

1

In Bezug auf die erste Antwort von Avi & Ev0oD. Abstrakte Klassen können nur erweitert und nicht implementiert werden.

public abstract class AppleFactory { 
    public abstract Apple createInstance(final String str); 
} 

public class AppleFactoryImpl extends AppleFactory { 
    public Apple createInstance(final String str) { // Implementation } 
}