2012-11-13 34 views
55

Tôi có một lớp học như sau:Mock một constructor với tham số

public class A { 
    public A(String test) { 
     bla bla bla 
    } 

    public String check() { 
     bla bla bla 
    } 
} 

Logic trong constructor A(String test)check() là những điều tôi đang cố gắng để chế nhạo. Tôi muốn có bất kỳ cuộc gọi nào như: new A($$$any string$$$).check() trả về một chuỗi giả "test".

tôi đã cố gắng:

A a = mock(A.class); 
when(a.check()).thenReturn("test"); 

String test = a.check(); // to this point, everything works. test shows as "tests" 

whenNew(A.class).withArguments(Matchers.anyString()).thenReturn(rk); 
// also tried: 
//whenNew(A.class).withParameterTypes(String.class).withArguments(Matchers.anyString()).thenReturn(rk); 

new A("random string").check(); // this doesn't work 

Nhưng nó dường như không được làm việc. new A($$$any string$$$).check() vẫn đang đi qua logic của hàm tạo thay vì tìm nạp đối tượng được giả lập là A.

+0

được kiểm tra chế giễu của bạn() phương pháp làm việc đúng không? –

+0

@BenGlasser check() hoạt động ok. Chỉ cần whenNew dường như không hoạt động chút nào. Tôi cũng cập nhật phần mô tả. – Shengjie

Trả lời

56

Mã bạn được đăng công trình cho tôi với các phiên bản mới nhất của Mockito và Powermockito. Có lẽ bạn chưa chuẩn bị A? Hãy thử điều này:

A.java

public class A { 
    private final String test; 

    public A(String test) { 
     this.test = test; 
    } 

    public String check() { 
     return "checked " + this.test; 
    } 
} 

MockA.java

import static org.hamcrest.MatcherAssert.assertThat; 
import static org.hamcrest.Matchers.equalTo; 
import static org.mockito.Mockito.mock; 
import static org.mockito.Mockito.when; 

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

@RunWith(PowerMockRunner.class) 
@PrepareForTest(A.class) 
public class MockA { 
    @Test 
    public void test_not_mocked() throws Throwable { 
     assertThat(new A("random string").check(), equalTo("checked random string")); 
    } 
    @Test 
    public void test_mocked() throws Throwable { 
     A a = mock(A.class); 
     when(a.check()).thenReturn("test"); 
     PowerMockito.whenNew(A.class).withArguments(Mockito.anyString()).thenReturn(a); 
     assertThat(new A("random string").check(), equalTo("test")); 
    } 
} 

Cả hai bài kiểm tra phải vượt qua với Mockito 1.9.0, 1.4.12 và powermockito junit 4.8.2

+13

Cũng lưu ý rằng nếu hàm tạo được gọi từ một lớp khác, hãy đưa nó vào danh sách trong 'PrepareForTest' –

33

Theo hiểu biết của tôi, bạn không thể giả lập các nhà xây dựng bằng phương pháp mockito, chỉ. Nhưng theo wiki trên trang mã Mockito google có một cách để giả lập hành vi của hàm tạo bằng cách tạo một phương thức trong lớp của bạn để trả về một cá thể mới của lớp đó. thì bạn có thể thử phương pháp đó. Dưới đây là một excerpt directly from the Mockito wiki:

Pattern 1 - sử dụng phương pháp một dòng để tạo đối tượng

Để sử dụng mô hình 1 (thử nghiệm một lớp được gọi là MyClass), bạn sẽ thay thế một cuộc gọi như

Foo foo = new Foo(a, b, c); 

với

Foo foo = makeFoo(a, b, c); 

và viết một dòng metho d

Foo makeFoo(A a, B b, C c) { 
     return new Foo(a, b, c); 
    } 

Điều quan trọng là bạn không bao gồm bất kỳ logic nào trong phương pháp; chỉ là một dòng tạo đối tượng . Lý do cho điều này là bản thân phương pháp sẽ không bao giờ đi để được kiểm tra đơn vị.

Khi bạn đến để kiểm tra lớp học, đối tượng bạn kiểm tra sẽ thực sự là một điệp viên Mockito, với phương pháp này được ghi đè, để trả về một mô hình . Do đó, những gì bạn đang thử nghiệm không phải là chính lớp đó, mà là một phiên bản được sửa đổi rất ít của phiên bản .

lớp thử nghiệm của bạn có thể chứa các thành viên như

@Mock private Foo mockFoo; 
    private MyClass toTest = spy(new MyClass()); 

Cuối cùng, bên trong phương pháp thử nghiệm của bạn, bạn thử ra các cuộc gọi đến makeFoo với một dòng như

doReturn(mockFoo) 
     .when(toTest) 
     .makeFoo(any(A.class), any(B.class), any(C.class)); 

Bạn có thể sử dụng quẹt rằng có nhiều cụ thể hơn bất kỳ() nếu bạn muốn kiểm tra các đối số được truyền cho hàm tạo.

Nếu bạn chỉ muốn trả lại đối tượng được mô phỏng của lớp, tôi nghĩ điều này sẽ phù hợp với bạn.Trong mọi trường hợp, bạn có thể đọc thêm về chế giễu đối tượng sáng tạo ở đây:

http://code.google.com/p/mockito/wiki/MockingObjectCreation

+10

+1, tôi không thích thực tế là tôi cần phải điều chỉnh mã nguồn của tôi làm cho nó thân thiện hơn với mockito. Cảm ơn bạn đã chia sẻ. – Shengjie

+15

Nó không bao giờ xấu để có mã nguồn đó là testable hơn, hoặc để tránh testability anti-patterns khi bạn viết mã của bạn. Nếu bạn viết nguồn dễ kiểm tra hơn, nó sẽ tự động được bảo trì hơn. Việc cô lập các lời gọi hàm tạo của bạn trong các phương thức riêng của chúng chỉ là một cách để đạt được điều này. –

8

Nếu không sử dụng Powermock .... Xem ví dụ dưới đây dựa trên câu trả lời của Ben Glasser vì nó đã cho tôi một số thời gian để tìm ra nó .. hy vọng rằng tiết kiệm một số lần ...

Original Class:

public class AClazz { 

    public void updateObject(CClazz cClazzObj) { 
     log.debug("Bundler set."); 
     cClazzObj.setBundler(new BClazz(cClazzObj, 10)); 
    } 
} 

Modified Class:

@Slf4j 
public class AClazz { 

    public void updateObject(CClazz cClazzObj) { 
     log.debug("Bundler set."); 
     cClazzObj.setBundler(getBObject(cClazzObj, 10)); 
    } 

    protected BClazz getBObject(CClazz cClazzObj, int i) { 
     return new BClazz(cClazzObj, 10); 
    } 
} 

Kiểm tra Lớp

public class AClazzTest { 

    @InjectMocks 
    @Spy 
    private AClazz aClazzObj; 

    @Mock 
    private CClazz cClazzObj; 

    @Mock 
    private BClazz bClassObj; 

    @Before 
    public void setUp() throws Exception { 
     Mockito.doReturn(bClassObj) 
       .when(aClazzObj) 
       .getBObject(Mockito.eq(cClazzObj), Mockito.anyInt()); 
    } 

    @Test 
    public void testConfigStrategy() { 
     aClazzObj.updateObject(cClazzObj); 

     Mockito.verify(cClazzObj, Mockito.times(1)).setBundler(bClassObj); 
    } 
} 
1

Mockito có những hạn chế thử nghiệm cuối cùng, sta tic, và phương pháp riêng.

với thư viện kiểm tra jMockit, bạn có thể làm vài thứ rất dễ dàng và thẳng về phía trước như sau:

constructor Mock của một lớp java.io.File:

new MockUp<File>(){ 
    @Mock 
    public void $init(String pathname){ 
     System.out.println(pathname); 
     // or do whatever you want 
    } 
}; 
  • các nhà xây dựng công cộng tên phải được thay thế bằng $ init
  • đối số và ngoại lệ được ném vẫn giữ nguyên
  • loại trả về phải được xác định là void

Mock một phương pháp tĩnh:

  • loại bỏ tĩnh từ phương pháp chữ ký giả
  • phương pháp chữ ký vẫn giống nhau khác
Các vấn đề liên quan