2017-01-23 5 views
2

Ich habe eine Methode in einer Klasse, die eine statische Klasseninstanz instanziieren und Operation darauf aufrufen.Mocking statische Klasse

public class SomeClass { 
    public void someMethod() { 
     MyClass.MyStaticClass myStaticClassInstance = 
      new MyClass.MyStaticClass(arg1, arg2, arg3); 
     myStaticClassInstance.callSomeMethod(); 
    } 
} 

public class MyClass { 

    public static class MyStaticClass { 

     public MyStaticClass(Object arg1, Object arg2, Object arg3) { 
     } 

     public void callSomeMethod() { 
     } 
    } 
} 

Wie statische Klasse Instanciation verspotten, so dass ich callSomeMethod() ohne Umweg über den statischen Konstruktor der Klasse verspotten könnte?

+0

yo Du solltest "MyStaticClass" in "SomeClass" überhaupt nicht instanziieren. Sie sollten * dependency inversion * verwenden, um eine Instanz von 'MyStaticClass' in die Instanz von' SomeClass' zu injizieren. –

Antwort

1

Sie können es mit PowerMock durch Spott Instintiation Ihrer statischen inneren Klasse tun. Dies kann durch Vorbereiten der Klasse geschehen, die tatsächlich Ihre statische innere Klasse instanziiert, so dass es hier die Klasse ist, in der Sie die Methode someMethod() definiert haben.

dass someMethod() Unter der Annahme, in der Klasse definiert MyOtherClass und gibt nichts zurück, Ihre Testklasse etwas so sein würde:

@RunWith(PowerMockRunner.class) // The runner of PowerMock 
@PrepareForTest(MyOtherClass.class) // the class to prepare 
public class MyClassTest { 

    @Test 
    public void test() throws Exception { 
     // The mock of your static inner class to return 
     MyClass.MyStaticClass mock = Mockito.mock(MyClass.MyStaticClass.class); 
     // Mock the call of callSomeMethod() 
     PowerMockito.doAnswer(
      new Answer<Void>() { 
       @Override 
       public Void answer(final InvocationOnMock invocation) throws Throwable { 
        // Do something here as new implementation of callSomeMethod 
        System.out.println("My new Answer"); 
        return null; 
       } 
      } 
     ).when(mock).callSomeMethod(); 
     // Return your mock in case we instantiate MyClass.MyStaticClass in 
     // the prepared class with any arguments 
     PowerMockito.whenNew(MyClass.MyStaticClass.class) 
      .withArguments(Matchers.any(), Matchers.any(), Matchers.any()) 
      .thenReturn(mock); 

     // The code that will call someMethod 
     MyOtherClass mc = new MyOtherClass(); 
     mc.someMethod(); 
    } 
} 

Unter der Annahme, dass meine Klasse MyClass wie folgt aussieht:

public class MyClass { 

    public static class MyStaticClass { 
     public MyStaticClass(Object arg1, Object arg2, Object arg3) { 
      System.out.println("Called constructor"); 
     } 

     public void callSomeMethod() { 
      System.out.println("callSomeMethod"); 
     } 
    } 
} 

Und Meine Klasse MyOtherClass sieht so aus:

public class MyOtherClass { 
    public void someMethod() { 
     MyClass.MyStaticClass myStaticClassInstance = new MyClass.MyStaticClass(
      new Object(), new Object(), new Object() 
     ); 
     myStaticClassInstance.callSomeMethod(); 
    } 
} 

Wenn ich meinen Test starten, erhalte ich als erwartet:

My new Answer 

Statt dessen, was ich standardmäßig bekommen sollte:

Called constructor 
callSomeMethod 

Mehr Details über how to constructions of new objects.

+0

Ja, es ist klar, aber es funktioniert nicht. Die Ausführung wird innerhalb des Konstruktors der statischen Klasse ausgeführt, wenn 'new MyClass.MyStaticClass (arg1, arg2, arg3); 'ausgeführt wird, was ich vermeiden möchte. – jerome

+0

Ich installiere nicht die statische Klasse innerhalb der öffentlichen Klasse, wo es definiert ist, das ist der Unterschied zu Ihrem Code. – jerome

+1

Ich ändere '@PrepareForTest (MyClass.class)' mit '@PrepareForTest (SomeClass .class)' und es funktioniert. Vielen Dank für Sie Code-Beispiel, es hat mir sehr geholfen. – jerome

0

Sie können PowerMockito mit Mockito verwenden, um diese Sache zu erledigen.

@RunWith(PowerMockRunner.class) 
@PrepareForTest(DriverManager.class) 
public class TestMocker { 

    @Test 
    public void testName() throws Exception { 

     //given 
     PowerMockito.mockStatic(DriverManager.class); 
     BDDMockito.given(DriverManager.getConnection(...)).willReturn(...); 

     //when 
     sut.execute(); 

     //then 
     PowerMockito.verifyStatic(); 
     DriverManager.getConnection(...); 

    } 

Hoffe, das hilft. Glückliche Kodierung!

0

Ich schrieb ein einfacheres Werkzeug für Dinge spöttisch, die normalerweise 'nicht mockable' bei https://github.com/iirekm/misc/tree/master/ajmock

Ihr Code sind, können wie folgt aussehen:

`` ` public class MyClassTest {

@Test 
public void test() throws Exception { 
    MyClass.MyStaticClass mock = Mockito.mock(MyClass.MyStaticClass.class); 
    when(() -> mock.callSomeMethod()).thenAnswer(() -> ...); 

    when(() -> new MyClass.MyStaticClass(any(), any(), any())).thenReturn(mock); 

    // The code that will call someMethod 
    MyOtherClass mc = new MyOtherClass(); 
    mc.someMethod(); 
} 

}

`` `

Verwandte Themen