2012-05-26 41 views
5

Tôi viết một kiểm tra đơn vị sử dụng JUnit + Mockito để thử nghiệm một phương pháp như:Mocking một cuộc gọi trên một phương pháp công cộng của một lớp trừu tượng mà không cần lớp con của lớp trừu tượng, sử dụng Mockito prefererably

public someObject methodUnderTest(){ 
    SomeObject obj = SomeAbstractClass.someMethod(); 

    if(obj!=null){ 
    obj.someOtherMethod(); 
    } 

    return someThing; 
} 

Và tôi muốn để thử cuộc gọi trên abstract Class "SomeAbstractClass" đề cập trong đoạn mã trên nên tôi có thể xác minh cuộc gọi trên "obj" như:

verify(SomeAbstractClass).someMethod(); 
verify(obj).someOtherMethod(); 

tôi đã cố gắng sử dụng các tính năng Mockito như: Mockito.CALLS_REAL_METHODS Mockito. RETURNS_MOCKS

nhưng chúng không hoạt động do phụ thuộc không có sẵn cho SomeAbstractClass.

Lưu ý:

1) SomeObject là Giao diện.

2) Tôi cần một kỹ thuật để kiểm tra đoạn mã trên. Tôi bị ràng buộc sử dụng đoạn mã trên và không thể thay đổi đoạn mã.

Trả lời

1

Giả định: nếu bạn viết kiểm tra đơn vị, tôi đoán bạn vẫn có thể sửa đổi phương pháp thử nghiệm một chút.

Giải pháp:

  1. trích phương pháp tĩnh gọi đến phương pháp overridable:
public someObject methodUnderTest() { 
    SomeObject obj = getSomeObject(); 

    if(obj!=null){ 
     obj.someOtherMethod(); 
    } 

    return someThing; 
} 

protected SomeObject getSomeObject() { 
    return SomeAbstractClass.someMethod(); 
} 
  1. sau đó bạn có thể sử dụng Mockito Spy để phần nhạo báng đối tượng bạn thực sự kiểm tra:
private ClassUnderTest classUnderTest; 

@Before 
public void setUp() { 
    classUnderTest= new ClassUnderTest(); 
    classUnderTest = Mockito.spy(classUnderTest); 
} 

@Test 
public void test() { 
    SomeObject someObject = Mockito.mock(SomeObject.class); 
    when(classUnderTest.getSomeObject()).thenReturn(someObject); 
    classUnderTest.methodUnderTest(); 
    verify(someObject).someOtherMethod(); 
} 

@Test 
public void testNull() { 
    when(classUnderTest.getSomeObject()).thenReturn(null); 
    classUnderTest.methodUnderTest(); 
    verify(something); 
} 
+0

Cảm ơn bạn đã giúp đỡ. Tôi đã làm điều tương tự. –

1

Sử dụng lớp nặc danh:

public interface SomeObject { 
    public Object someOtherMethod(); 
} 

public abstract class SomeAbstractClass { 
    abstract SomeObject someMethod(); 
} 

@Test 
public void test() { 
    SomeAbstractClass target = new SomeAbstractClass() { 
     SomeObject someMethod() { 
      // some impl 
      SomeObject someObject = new SomeObject() { 
       public Object someOtherMethod() { 
        // some other impl 
       } 
      }; 
      return someObject; 
     } 
    }; 

    // now test target 
} 
+0

Cảm ơn Bohemian, nhưng tôi quên đề cập rằng SomeObject trả về là một Giao diện cũng như "SomeAbstractClass.someMethod()" là phương thức công khai và tĩnh. Do đó tôi buộc phải triển khai Giao diện "SomeObject" mà tôi không muốn làm, cả "SomeAbstractClass" và "SomeObject" là một phần của thư viện của bên thứ ba mà tôi đang sử dụng trong ứng dụng web của mình. –

+0

Bạn cũng có thể sử dụng lớp ẩn danh cho giao diện (như SomeObject) - xem câu trả lời đã chỉnh sửa – Bohemian

2

Bạn có thể sử dụng PowerMock để thử phương pháp tĩnh và cuối cùng.

2

Nghe có vẻ như vấn đề là việc bạn sử dụng CALLS_REAL_METHODS đang áp dụng cho toàn bộ lớp, nơi mà bạn thực sự muốn thử ra phương pháp cụ thể (ví dụ: tạo một "mô hình một phần"). Bạn có hai lựa chọn ở đây, người ta sử dụng thenCallRealMethod, và một sử dụng CALLS_REAL_METHODS và sau đó đặc biệt chế giễu các cuộc gọi mà bạn cần:

public void testMethodUnderTest_mockSpecificThings() { 
    SomeAbstractClass myAbstractClass = Mockito.mock(SomeAbstractClass.class); 
    SomeAbstractClass myObject = Mockito.mock(SomeObject.class); 
    when(myAbstractClass.someMethod()).thenReturn(foo); 
    when(myAbstractClass.methodUnderTest()).thenCallRealMethod(); 

    myAbstractClass.methodUnderTest(); 

    verify(myAbstractClass).someMethod(); 
    verify(myObject).someOtherMethod(); 
} 

public void testMethodUnderTest_makeSpecificRealCalls() { 
    SomeAbstractClass myAbstractClass = 
     Mockito.mock(SomeAbstractClass.class, CALLS_REAL_METHODS); 
    SomeAbstractClass myObject = Mockito.mock(SomeObject.class); 
    // overrides the default answer 
    when(myAbstractClass.someMethod()).thenReturn(myObject); 

    myAbstractClass.methodUnderTest(); 

    verify(myAbstractClass).someMethod(); 
    verify(myObject).someOtherMethod(); 
} 

Được cảnh báo trước rằng SomeAbstractClass không bao giờ thực sự khởi tạo, vì vậy nếu bạn dựa vào hành vi nào ở các lớp trừu tượng constructor, như khởi tạo biến - bao gồm khởi tạo nội tuyến nơi các trường được khai báo - bạn sẽ cần phải thực hiện những cuộc gọi đó một cách rõ ràng cho chính mình.

Các vấn đề liên quan