2011-11-08 30 views
23

Tôi đang cố gắng chế nhạo một phương thức riêng tư đang thực hiện cuộc gọi JNDI. Khi phương thức đó được gọi từ một phép thử đơn vị, nó sẽ ném ra một ngoại lệ ^. Tôi muốn mô phỏng phương pháp đó cho mục đích thử nghiệm. Tôi đã sử dụng sample code from another questions answer và trong khi thử nghiệm được chuyển, có vẻ như phương thức cơ bản vẫn được gọi. Tôi đã chèn một số System.err.println() vào phương thức doTheGamble() và được in ra bảng điều khiển của tôi.Phương thức riêng được giả lập với PowerMock, nhưng phương thức cơ bản vẫn được gọi là

Điều thú vị đủ, nếu tôi nhận xét số assertThat đầu tiên, bài kiểm tra sẽ trôi qua. ? :(

Vì vậy, làm thế nào để tôi thử ra một phương pháp riêng để nó không được gọi là?

import static org.hamcrest.core.Is.is; 
import static org.junit.Assert.assertThat; 
import static org.mockito.Matchers.anyInt; 
import static org.mockito.Matchers.anyString; 
import static org.powermock.api.mockito.PowerMockito.when; 
import static org.powermock.api.support.membermodification.MemberMatcher.method; 

import java.util.Random; 

import org.junit.Test; 
import org.junit.runner.RunWith; 
import org.powermock.api.mockito.PowerMockito; 
import org.powermock.core.classloader.annotations.PrepareForTest; 
import org.powermock.modules.junit4.PowerMockRunner; 

@RunWith(PowerMockRunner.class) 
@PrepareForTest(CodeWithPrivateMethod.class) 
public class PowerMock_Test { 

    static boolean gambleCalled = false; 

    @Test(expected = RuntimeException.class) 
    public void when_gambling_is_true_then_always_explode() throws Exception { 
     CodeWithPrivateMethod spy = PowerMockito.spy(new CodeWithPrivateMethod()); 

     when(spy, method(CodeWithPrivateMethod.class, "doTheGamble", String.class, int.class)) 
       .withArguments(anyString(), anyInt()) 
       .thenReturn(true); 

/* 1 */ assertThat(PowerMock_Test.gambleCalled, is(false)); 
     spy.meaningfulPublicApi(); 
/* 2 */ assertThat(PowerMock_Test.gambleCalled, is(false)); 
    } 
} 


class CodeWithPrivateMethod { 

    public void meaningfulPublicApi() { 
     if (doTheGamble("Whatever", 1 << 3)) { 
      throw new RuntimeException("boom"); 
     } 
    } 

    private boolean doTheGamble(String whatever, int binary) { 
     Random random = new Random(System.nanoTime()); 
     boolean gamble = random.nextBoolean(); 

     System.err.println("\n>>> GAMBLE CALLED <<<\n"); 
     PowerMock_Test.gambleCalled = true; 

     return gamble; 
    } 
} 

^dễ hiểu, vì không gian làm việc của tôi không hỗ trợ JNDI, chỉ có môi trường sản xuất không

% tôi đang sử dụng phiên bản mới nhất của tất cả các thư viện, JUnit 4.10, Mockito 1.8.5, hamcrest 1.1, Javassist 3.15.0, và PowerMock 1.4.10.

Trả lời

29

Từ PowerMock Private Method Example:

@RunWith(PowerMockRunner.class) 
// We prepare PartialMockClass for test because it's final or we need to mock private or static methods 
@PrepareForTest(PartialMockClass.class) 
public class YourTestCase { 
@Test 
public void privatePartialMockingWithPowerMock() {   
    PartialMockClass classUnderTest = PowerMockito.spy(new PartialMockClass()); 

    // use PowerMockito to set up your expectation 
    PowerMockito.doReturn(value).when(classUnderTest, "methodToMock", "parameter1"); 

    // execute your test 
    classUnderTest.execute(); 

    // Use PowerMockito.verify() to verify result 
    PowerMockito.verifyPrivate(classUnderTest, times(2)).invoke("methodToMock", "parameter1"); 
} 

Vì vậy, để áp dụng điều này để mã của bạn, tôi nghĩ rằng nó có thể trở thành:

@RunWith(PowerMockRunner.class) 
@PrepareForTest(CodeWithPrivateMethod.class) 
public class PowerMock_Test { 
    @Test(expected = RuntimeException.class) 
    public void when_gambling_is_true_then_always_explode() throws Exception { 
     CodeWithPrivateMethod spy = PowerMockito.spy(new CodeWithPrivateMethod()); 

     PowerMockito.doReturn(true).when(spy, "doTheGamble", anyString(), anyInt()); 


/* 1 */ PowerMockito.verifyPrivate(spy, times(0)).invoke("doTheGamble", anyString(), anyInt());    
     spy.meaningfulPublicApi(); 
/* 2 */ PowerMockito.verifyPrivate(spy, times(2)).invoke("doTheGamble", anyString(), anyInt());    
    } 
} 

Tôi chỉ mã hóa mà trong trình soạn thảo ở đây. Không có thử nghiệm nào thực sự được chạy và không có lỗi nào bị tổn hại trong việc tạo mã này.

+8

+1 để không gây hại cho các lỗi. Rất quan tâm đến bạn;) – Guillaume

+0

@Mike Bạn có biết tại sao 'doReturn (true) .when (spy," doTheGamble ", anyString(), anyInt());' hoạt động nhưng 'doReturn (true) .when (spy , method (CodeWithPrivateMethod.class, "doTheGamble", String.class, int.class)) .withArguments (anyString(), anyInt()); 'kết quả trong một' IllegalArgumentException: kiểu đối số không khớp '? Sau này có vẻ phù hợp hơn với phong cách của ví dụ và ít nhất là tương đương nhưng không hoạt động. – ArtB

+0

Tôi thành thật không thể, xin lỗi. Tôi khá mới mẻ với bản thân Mockito/PowerMock ... Tôi chưa bao giờ thử viết mã theo kiểu đó ('.withArguments (...)') trước đây. – Mike

0

khi bạn sử dụng spy để xây dựng một đối tượng giả, một nửa đối tượng thực sự được hỗ trợ của nó. để loại bỏ spy. Làm việc trên đối tượng giả tinh khiết.

+1

Tôi đang cố gắng kiểm tra việc triển khai lớp mà tôi đang gián điệp vì vậy đây không phải là một tùy chọn. – ArtB

1

ArtB,

Bạn có chắc chắn mã của bạn không hoạt động (hoặc) am i thiếu cái gì ở đây? Tôi vừa thay thế phương thức kỳ vọng của bạn theo cách mà Mike đã đề xuất và nó hoạt động tốt:

PowerMockito.doReturn(true).when(spy, 
       method(CodeWithPrivateMethod.class, "doTheGamble", String.class, int.class)) 
       .withArguments(anyString(), anyInt()); 

Tôi chưa từng sử dụng Powermockito nhưng đã sử dụng Mockito trước đây.

+0

Có, tôi chắc chắn, tôi sẽ PasteBin lên một số đầu ra một khi tôi nhận được để làm việc. – ArtB

2

ArtB,

Chỉ cần dán mã hoàn chỉnh hoạt động tốt trong IDE Eclipse của tôi. Tôi chỉ thay đổi kỳ vọng tôi đã nói trong bài viết trước. Chúc may mắn.

import static org.hamcrest.core.Is.is; 
import static org.junit.Assert.assertThat; 
import static org.mockito.Matchers.anyInt; 
import static org.mockito.Matchers.anyString; 
import static org.powermock.api.support.membermodification.MemberMatcher.method; 

import java.util.Random; 

import org.junit.Test; 
import org.junit.runner.RunWith; 
import org.powermock.api.mockito.PowerMockito; 
import org.powermock.core.classloader.annotations.PrepareForTest; 
import org.powermock.modules.junit4.PowerMockRunner; 

@RunWith(PowerMockRunner.class) 
@PrepareForTest(CodeWithPrivateMethod.class) 
public class PowerMock_Test { 

    static boolean gambleCalled = false; 

    @Test(expected = RuntimeException.class) 
    public void when_gambling_is_true_then_always_explode() throws Exception { 
     CodeWithPrivateMethod spy = PowerMockito.spy(new CodeWithPrivateMethod()); 

//  PowerMockito.doReturn(true).when(spy, "doTheGamble", anyString(), anyInt()); 

     PowerMockito.doReturn(true).when(spy, 
       method(CodeWithPrivateMethod.class, "doTheGamble", String.class, int.class)) 
       .withArguments(anyString(), anyInt()); 

     assertThat(PowerMock_Test.gambleCalled, is(false)); 
     spy.meaningfulPublicApi(); 
     assertThat(PowerMock_Test.gambleCalled, is(false)); 
    } 
} 


class CodeWithPrivateMethod { 

    public void meaningfulPublicApi() { 
     if (doTheGamble("Whatever", 1 << 3)) { 
      throw new RuntimeException("boom"); 
     } 
    } 

    private boolean doTheGamble(String whatever, int binary) { 
     Random random = new Random(System.nanoTime()); 
     boolean gamble = random.nextBoolean(); 

     System.err.println("\n>>> GAMBLE CALLED <<<\n"); 
     PowerMock_Test.gambleCalled = true; 

     return gamble; 
    } 
} 
Các vấn đề liên quan