2015-06-08 10 views
29

Używam prywatny statyczny końcowy LOGGER pola w mojej klasie i chcę LOGGER.isInfoEnabled() sposób, aby powrócić fałszywy. Jak można drwić statycznego pola końcowego za pomocą Mockito lub jMockitMock private static final pole używając Mockito lub Jmockit

moja klasa jest:

import org.slf4j.Logger; 
    import org.slf4j.LoggerFactory; 

    public class Class1 { 

    private static final Logger LOGGER = LoggerFactory.getLogger(Class1.class); 

    public boolean demoMethod() { 
     System.out.println("Demo started"); 
     if (LOGGER.isInfoEnabled()) { 
     System.out.println("@@@@@@@@@@@@@@ ------- info is enabled"); 
     } else { 
     System.out.println("info is disabled"); 
     } 
     return LOGGER.isInfoEnabled(); 
    } 
    } 

i jego JUnit jest:

import mockit.Mocked; 
import mockit.NonStrictExpectations; 
import org.mockito.InjectMocks; 
import org.mockito.MockitoAnnotations; 
import org.slf4j.Logger; 
import org.testng.annotations.BeforeMethod; 
import org.testng.annotations.Test; 

import static org.testng.Assert.*; 
import com.source.Class1; 

public class MyTest { 

    @InjectMocks 
    Class1 cls1; 

    @BeforeMethod 
    public void initMocks() { 
    MockitoAnnotations.initMocks(this); 
    } 

    @Test 
    public void test(@Mocked final Logger LOGGER) { 

    new NonStrictExpectations() { 
     { 
     LOGGER.isInfoEnabled(); 
     result = false; 
     } 
    }; 
    assertFalse(cls1.demoMethod()); 
    } 
} 

gdy uruchomię go wynikiem jest:

------------------------------------------------------- 
T E S T S 
------------------------------------------------------- 
Running com.test.MyTest 
Configuring TestNG with: TestNG652Configurator 
Demo started 
@@@@@@@@@@@@@@ ------- info is enabled 
Tests run: 1, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 1.9 sec <<< FAILURE! - in com.test.MyTest 
test(com.test.MyTest) Time elapsed: 0.168 sec <<< FAILURE! 
java.lang.AssertionError: expected [false] but found [true] 
     at com.test.MyTest.test(MyTest.java:35) 


Results : 

Failed tests: 
    MyTest.test:35 expected [false] but found [true] 

Tests run: 1, Failures: 1, Errors: 0, Skipped: 0 

[INFO] ------------------------------------------------------------------------ 
[INFO] BUILD FAILURE 
[INFO] ------------------------------------------------------------------------ 
[INFO] Total time: 9.899s 
[INFO] Finished at: Mon Jun 08 12:35:36 IST 2015 
[INFO] Final Memory: 16M/166M 
[INFO] ------------------------------------------------------------------------ 
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.18.1:test (default-test) on project JMockDemo: The 
re are test failures. 
[ERROR] 
[ERROR] Please refer to D:\perfoce_code\workspace_kepler\JMockDemo\target\surefire-reports for the individual test results. 
[ERROR] -> [Help 1] 
[ERROR] 
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch. 
[ERROR] Re-run Maven using the -X switch to enable full debug logging. 
[ERROR] 
[ERROR] For more information about the errors and possible solutions, please read the following articles: 
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException 

Jestem nowy w firmie jmockit i chcę, aby mój poprzedni przypadek działał poprawnie. I muszę używać JMockit lub mockito, nie można używać Powermockito. Proszę o pomoc.

+0

Można utworzyć metody setter dla tych elementów i ustawić mock rejestratora podczas testów. –

+0

Tak to działa w ten sposób, ale muszę uczynić program rejestrujący nie końcowym, a także dodać metodę ustawiającą. Nie ma sposobu, żeby to zrobić bez zmiany faktycznej klasy. –

+3

Wystarczy zmienić '@Mocked Logger' na' @Capturing Logger', to powinno działać. –

Odpowiedz

35

Jednym ze sposobów jest użycie odbicie pozbyć final modyfikator z pola, a następnie zastąpić pole LOGGER szydzili z jednej

public class Class1Test { 
    @Test 
    public void test() throws Exception { 
     Logger logger = Mockito.mock(Logger.class); 
     Mockito.when(logger.isInfoEnabled()).thenReturn(false); 
     setFinalStatic(Class1.class.getDeclaredField("LOGGER"), logger); 
     Class1 cls1 = new Class1(); 
     assertFalse(cls1.demoMethod()); 
    } 

    static void setFinalStatic(Field field, Object newValue) throws Exception { 
     field.setAccessible(true);   
     Field modifiersField = Field.class.getDeclaredField("modifiers"); 
     modifiersField.setAccessible(true); 
     modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); 
     field.set(null, newValue); 
    } 
} 
+0

Wow świetnie, to rozwiązanie, którego szukałem, dziękuję bardzo :-) –

+0

Dlaczego ustawiłeś metodę setFinalStatic, czy istnieje jakaś konkretna przyczyna? –

+9

To bardzo niebezpieczne, ponieważ zmienia statyczną instancję dla całej klasy ClassLoader. Każdy kolejny test/klasa będzie miał wyśmiewane wystąpienie rejestratora. Tego nie należy również używać podczas równoległego wykonywania testów. Może to prowadzić do poważnych problemów z wieloma wątkami w twoich testach, bądź ostrożny. –

1

Myślę, że mockito lub jMockit nie mogą symulować statycznych klas końcowych, ponieważ próbują zastąpić metody podczas testowania jednostkowego. PowerMockito może jednak używać Reflection i wyśmiewa statyczną ostatnią klasę/metody.

+1

Nie można przesłonić ostatecznych metod. Możesz to zrobić tylko, jeśli używasz refleksji. –

Powiązane problemy