2013-07-16 25 views
6

Tôi có một lớp học như sau;Giả lập một trường tĩnh riêng với JMockit?

class ClassA { 
    private static File myDir; 

    // myDir is created at some stage 

    private static String findFile(final String fileName) { 
     for (final String actualBackupFileName : myDir.list()) { 
      if (actualBackupFileName.startsWith(removeExtensionFrom(backupFile))) { 
       return actualBackupFileName; 
      } 
     } 
    } 
} 

Vì vậy, về cơ bản, tôi muốn kiểm tra lớp này bằng cách chế giễu ra lớp File để khi danh sách() được gọi vào nó nó trả về một danh sách các chuỗi Tôi định nghĩa trong lớp thử nghiệm của tôi.

Tôi đã có những điều sau đây nhưng nó không hoạt động vào phút, có lẽ có điều gì đó hiển nhiên tôi đang làm sai - Tôi mới làm quen với JMockit - bất kỳ trợ giúp nào được đánh giá cao!

@Mocked("list") File myDir; 

@Test 
    public void testClassA() { 
    final String[] files = {"file1-bla.txt"}; 

    new NonStrictExpectations() {{ 
     new File(anyString).list(); 
     returns(files); 
    }}; 

    String returnedFileName = Deencapsulation.invoke(ClassA.class, "findFile","file1.txt"); 

    // assert returnedFileName is equal to "file1-bla.txt" 
    } 

Khi chạy thử nghiệm ở trên, tôi nhận được NullPointerChú ý cho trường myDir trong ClassA - vì vậy có vẻ như nó không bị giả mạo đúng cách?

Trả lời

10

JMockit (hoặc bất kỳ công cụ chế giễu khác) không ruộng giả hoặc các biến, nó chế giễu loại (lớp, giao diện, vv) Trong trường hợp các trường hợp của những loại được được lưu trữ bên trong mã đang thử nghiệm không có liên quan.

kiểm tra Ví dụ cho ClassA:

@Test 
public void testClassA(@Mocked File myDir) 
{ 
    new Expectations() {{ myDir.list(); result = "file1-bla.txt"; }}; 

    String returnedFileName = new ClassA().publicMethodThatCallsFindFile("file1.txt"); 

    assertEquals("file1-bla.txt", returnedFileName); 
} 

Trên đây nên làm việc. Lưu ý rằng việc kiểm tra trực tiếp các phương thức private (hoặc truy cập private trường) được coi là thực hành không tốt, vì vậy tôi tránh nó ở đây. Ngoài ra, tốt nhất là tránh chế nhạo lớp File. Thay vào đó, chỉ thử nghiệm các phương thức public của bạn và sử dụng các tệp thực tế thay vì chế nhạo hệ thống tệp.

+0

Tuyệt vời, cảm ơn một triệu cho sự giúp đỡ của bạn Rogerio, điều này đã làm việc với một thay đổi nhỏ đối với mã của bạn - @Mocked File myDir phải được đổi thành @Mocked (phương thức = {"list"}) File myDir để làm cho nó hoạt động. Tôi nghĩ rằng điều này có thể là do cuộc gọi Deencapsualtion.invoke có thể cần một đối tượng File thực tại một thời điểm nào đó, và chế giễu tất cả các phương pháp dường như can thiệp vào một thứ gì đó. Tôi là người dùng mới nên không thể bỏ phiếu cho bạn - nếu không tôi sẽ làm! – user2586917

+1

Tuyệt vời! Mocking 'File' thực sự có thể gây ra lỗi không mong muốn, ít nhất là trong các phiên bản cũ của JMockit. Tôi đã chỉnh sửa câu trả lời với các thay đổi của bạn. –

+0

@ Rogério, cách trên tạo một đối tượng giả ('myDir') dẫn đến tham chiếu là' null', khiến 'myDir.list()' thất bại với 'NPE'. Bất kỳ ý tưởng tại sao? – mystarrocks

0

thử này:

new Expectations {{ 
    invoke(File.class, "list", null, null); 
    returns(files); 
}} 
+1

Cảm ơn, nhưng các tài liệu nói gọi là gọi một phương thức tĩnh - list() trên Tệp không tĩnh - dường như không hoạt động. – user2586917

7

Bạn có thể sử dụng phương thức setField từ lớp Deencapsulation. Lưu ý ví dụ bên dưới:

Deencapsulation.setField(ClassA, "File", your_desired_value); 
Các vấn đề liên quan