Điều này chắc chắn không trả lời câu hỏi của bạn, nhưng theo ý kiến trung thực của tôi nó có liên quan, nó hữu ích và quá lớn để nhận xét.
Tôi thường phải đối mặt với câu hỏi này và tôi luôn luôn làm "tiêm phụ thuộc xây dựng". Điều này có nghĩa là tôi không còn làm tiêm lĩnh vực bằng cách chú thích lĩnh vực với @Inject
nhưng vượt qua sự phụ thuộc vào các nhà xây dựng như sau:
public class MyClassDoingSomething implements DoSomethig {
private final Service mainService;
@Inject
public MyClassDoingSomething(Service mainService) {
this.mainService = mainService;
}
}
Thông báo như thế nào các nhà xây dựng hiện nay nhận được thông số và thiết lập các lĩnh vực để nó và là cũng được chú thích với @Inject
? Tôi cũng muốn làm cho các lớp này thực hiện một giao diện (cũng cho MyService
) - Trong số nhiều lợi ích khác mà tôi tìm thấy nó làm cho các mô-đun dao găm dễ dàng hơn để viết:
@Module
public class DoSomethingModule {
@Provides @Singleton public RestService provideRestService() {
return new RestService();
}
@Provides @Singleton public MyPrinter provideMyPrinter() {
return new MyPrinter();
}
@Provides @Singleton public Service provideMyPrinter(MyService service) {
return service;
}
@Provides @Singleton public DoSomethig provideMyPrinter(MyClassDoingSomething something) {
return something;
}
}
(này giả định rằng MyService
dụng cụ hoặc kéo dài Service
)
Bây giờ có vẻ như bạn đã biết rằng dao găm có thể tự mình tìm ra biểu đồ phụ thuộc và xây dựng tất cả các đối tượng cho bạn. Vì vậy, những gì về đơn vị kiểm tra lớp MyClassDoingSomething
? Tôi thậm chí không dùng dao găm ở đây. Tôi chỉ cần cung cấp phụ thuộc theo cách thủ công:
public class MyClassDoingSomethingTest {
@Mock
Service service;
private MyClassDoingSomething something;
@Before
public void setUp() throws Exception {
MockitoAnnotations.init(this);
something = new MyClassDoingSomething(service);
}
// ...
}
Như bạn thấy, phụ thuộc được truyền qua phương thức khởi tạo thủ công.
Rõ ràng điều này không hoạt động nếu bạn đang mã hóa thứ gì đó không có hàm tạo có thể được bạn gọi. Ví dụ cổ điển là các hoạt động, đoạn hoặc lượt xem trên Android. Có nhiều cách để đạt được điều đó, nhưng cá nhân tôi vẫn nghĩ rằng bạn bằng cách nào đó có thể vượt qua điều này mà không cần dao găm. Nếu bạn là đơn vị thử nghiệm một quan điểm cho rằng có một trường @Inject MyPresenter myPresenter
, thường là lĩnh vực này sẽ có quyền truy cập gói hoạt động tốt trong các bài kiểm tra:
public class MyViewTest {
@Mock MyPresenter presenter;
private MyView view;
@Before
public void setUp() throws Exception {
MockitoAnnotations.init(this);
view.myPresenter = presenter;
}
}
Lưu ý rằng đây chỉ hoạt động nếu cả hai MyViewTest
và MyView
là trong cùng một gói (thường là trường hợp trong các dự án android).
Vào cuối ngày, nếu bạn vẫn muốn sử dụng dao găm cho các bài kiểm tra, bạn luôn có thể tạo ra "thử nghiệm" mô-đun và các thành phần có thể tiêm bằng cách tuyên bố phương pháp trong các thành phần như:
@Inject
public interface MyTestComponent {
void inject(MyClassDoingSomething something);
}
tôi tìm cách tiếp cận này ok-ish, nhưng trong suốt những năm phát triển của tôi, tôi thích cách tiếp cận đầu tiên hơn. Điều này cũng đã báo cáo các vấn đề với Robolectric
rằng một số thiết lập trong tệp build.gradle
là bắt buộc để thực sự làm cho trình biên dịch dagger chạy cho các bài kiểm tra để các lớp thực sự được tạo.
Hãy nhớ rằng việc sử dụng các thành phần Dagger trong _unit testing_ là không bình thường khi thẻ của bạn cho biết; để kiểm tra đơn vị, hãy tự gọi các nhà xây dựng và chuyển vào càng nhiều mock như bạn muốn. Đối với thử nghiệm _integration_, _system_ hoặc _end-to-end_, việc sử dụng thành phần Dagger thực sự có ý nghĩa hơn nhiều, nhưng sau đó nó cũng có ý nghĩa hơn nhiều khi sử dụng các phụ thuộc thực sự cho một thử nghiệm thực tế. –
Cảm ơn @JeffBowman. Tôi có thể gây nhầm lẫn cho bạn về ý định của tôi do tên lớp. Tôi đã đổi tên MyClassToTest thành MyClassDoingSomething. vì đó không phải là một lớp Test, mà là một lớp thực tế. Bài kiểm tra đơn vị cho nó sẽ là một lớp khác không được định nghĩa trong câu hỏi của tôi ở trên. Trong trường hợp tôi đang thử nghiệm đơn vị một chức năng tức là myPublicFunction trong MyClassDoingSomething đang sử dụng mainService, tôi sẽ cần một gói mainService giả vào MyClassDoingSomething. Tôi biết làm thế nào để tiêm, nhưng không thể có được một giả của MyService tiêm thay vì đối tượng thực sự. – Elye
Xin chào. Bạn có tìm thấy câu trả lời cuối cùng không? Tôi bị kẹt với cùng một vấn đề: https://stackoverflow.com/questions/45166990/mock-injected-viewmodel –