2012-06-01 23 views
6

Tôi có một lớp mà Runtime.getRuntime() được sử dụng để thực thi một kịch bản từ dòng lệnh và nhận kết quả để xử lý tiếp.Làm thế nào để đi xung quanh Runtime.getRuntime() trong khi viết JUnit?

Nhưng khi tôi viết JUnit cho lớp này, tôi không thể tìm cách để giả lập/tránh Runtime.getRuntime(). Exec() này.

Tôi không thể sử dụng EasyMock hoặc PowerMock hoặc bất kỳ api mô phỏng nào khác ngoài Mockito.

Vui lòng cho tôi cách khắc phục sự cố này, vì điều này ảnh hưởng đến phạm vi mã.

Trả lời

13

Bạn phải tái cấu trúc. Trích xuất Runtime.getRuntime().exec() thành một lớp riêng biệt:

public class Shell { 

    public Process exec(String command) { 
    return Runtime.getRuntime().exec(command); 
    } 

} 

Bây giờ insted gọi getRuntime() tiêm một cách rõ ràng Shell lớp bằng cách nào đó để lớp học của bạn được kiểm tra:

public class Foo { 

    private final Shell shell; 

    public Foo(Shell shell) { 
    this.shell = shell; 
    } 

    //... 
    shell.exec(...) 

} 

Trong thử nghiệm JUnit đơn giản tiêm chế giễu Shell lớp bằng cách đi qua nó để xây dựng :

@Mock 
private Shell shellMock; 

new Foo(shellMock); 

Sidenote: yes, I am not tạo giao diện Shell với một triển khai. Bạn có phiền? Mockito thì không. Phần thưởng: bạn hiện có thể xác minh xem quy trình chính xác có được gọi là:

verify(shellMock).exec("/usr/bin/gimp"); 
+0

HI, Cảm ơn bạn đã trả lời nhanh !! – unni

+0

Nhưng, vẫn còn một số cách khác có thể? Tôi không phải thay đổi hàm tạo ở đâu? Không sử dụng setter như 'this.shell = shell;' – unni

+0

@ user1147417: Tôi không thấy bất kỳ khả năng nào, ít nhất là không có PowerMock. 'tĩnh' là ác! –

3

Tomasz Nurkiewicz đã cung cấp câu trả lời tuyệt vời. Nhưng có một sự thay thế.

Bạn có thể di chuyển Runtime.getRuntime() vào phương pháp riêng của mình trong lớp mà bạn đang thử nghiệm; sau đó kiểm tra nó với một điệp viên Mockito. Trong điệp viên Mockito, bạn có thể ghi đè phương pháp cụ thể này bằng phiên bản tạo ra một mô hình Runtime, sau đó thực hiện bất cứ điều gì bạn thích với nó.

Tuy nhiên, cách tiếp cận của Tomasz là sạch hơn và tôi khuyên bạn nên sử dụng kỹ lưỡng. Tôi chỉ muốn nói rằng có một cách khác để làm điều đó, mà không cần đến Powermock.

+0

oops David, tôi không thấy câu trả lời của bạn trước khi đăng lại một lần nữa. Cảm ơn bạn rất nhiều vì đã cung cấp một giải pháp tuyệt vời. – unni

0

tôi đã sử dụng sub-classing và trọng (như đã giải thích trong cuốn sách của Michael C. Feathers' "Làm việc hiệu quả với mã di sản")

Giả sử chúng ta có đoạn mã sau:

public class CannotChange{ 
    public CannotChange(){} 
    public void TryingToTest() throws IOException { 
     ... 
     Process proc = Runtime.getRuntime().exec("command"); 
     ... 
    } 
} 

Giải nén runtime mã vào một phương pháp bảo vệ:

public void TryingToTest() throws IOException { 
     ... 
     Process proc = execute("command"); 
     ... 
    } 
    protected Process execute(string command){ 
     return Runtime.getRuntime().exec(command); 
    }  

Sau đó, trong lớp thử nghiệm tạo ra một lớp mà kéo dài lớp CannotChange và ghi đè thực hiện

public class CannotChangeTest{ 

    private class CannotChangeForTesting extends CannotChange{ 
     public CannotChangeForTesting(){ super(); } 
     @Override 
     public Process execute(String command){ 
     return null; //or a mocked object 
     } 
    } 

    @Test 
    public void TestMethod(){ 
     CannotChange cannotChange = new ForTestCannotChange(); 
     cannotChange.TryingToTest(); 
    } 
} 
Các vấn đề liên quan