問題描述
因此,我被要求為我們的開發團隊閱讀有關 mocking 和 BDD 的內容,并使用 mocks 來改進我們現有的一些單元測試(作為實驗).
So I have been asked to read up on mocking and BDD for our development team and play around with mocks so as to improve a handful of our existing unit tests (as an experiment).
我最終選擇使用 Mockito 的原因有很多(有些原因超出了我的控制范圍),但就是因為它同時支持存根和模擬,以便在不適合模擬的情況下使用.
I have ultimately chosen to go with Mockito for a number of reasons (some outside the scope of my control), but namely because it supports both stubbing and mocking for instances when mocking would not be appropriate.
我整天都在學習 Mockito、mock(一般)和 BDD.現在我已準備好深入研究并開始擴充我們的單元測試.
I have spent all day learning about Mockito, mocking (in general) and BDD. And now I am ready to dig in and start augmenting our unit tests.
所以我們有一個名為 WebAdaptor
的類,它有一個 run()
方法:
So we have a class called WebAdaptor
that has a run()
method:
public class WebAdaptor {
private Subscriber subscriber;
public void run() {
subscriber = new Subscriber();
subscriber.init();
}
}
請注意:我無法修改此代碼(出于此問題范圍之外的原因!).因此我確實不有能力為Subscriber
添加一個setter方法,因此它可以被認為是我的WebAdaptor代碼>.
Please note: I do not have a way to modify this code (for reasons outside the scope of this question!). Thus I do not have the ability to add a setter method for Subscriber
, and thus it can be thought of as an unreachable "blackbox" inside of my WebAdaptor
.
我想編寫一個包含 Mockito
模擬的單元測試,并使用該模擬來 verify
執行 WebAdaptor::run()
導致 Subscriber::init()
被調用.
I want to write a unit test which incorporates a Mockito
mock, and uses that mock to verify
that executing WebAdaptor::run()
causes Subscriber::init()
to be called.
這就是我目前所得到的(在 WebAdaptorUnitTest
內):
So here's what I've got so far (inside WebAdaptorUnitTest
):
@Test
public void runShouldInvokeSubscriberInit() {
// Given
Subscriber mockSubscriber = mock(Subscriber.class);
WebAdaptor adaptor = new WebAdaptor();
// When
adaptor.run();
// Then
verify(mockSubscriber).init();
}
當我運行這個測試時,實際的 Subscriber::init()
方法會被執行(我可以從控制臺輸出和本地系統上生成的文件中看出),不是 mockSubscriber
,它不應該做(或返回)任何事情.
When I run this test, the actual Subscriber::init()
method gets executed (I can tell from the console output and seeing files being generated on my local system), not the mockSubscriber
, which shouldn't do (or return) anything.
我已經檢查并重新檢查:init
是 public
,既不是 static
也不是 final
,并且它返回 void
.根據文檔,Mockito 模擬這個對象應該沒有問題.
I have checked and re-checked: init
is public
, is neither static
or final
, and it returns void
. According to the docs, Mockito should have no problem mocking this object.
所以我開始思考:我是否需要明確地將 mockSubscriber
與 adaptor
關聯起來?如果是這種情況,那么通常情況下,以下通常會解決它:
So it got me thinking: do I need to explictly associate the mockSubscriber
with the adaptor
? If this is a case, then ordinarily, the following would normally fix it:
adaptor.setSubscriber(mockSubscriber);
但由于我無法添加任何這樣的設置器(請閱讀我上面的注釋),我不知道如何強制這樣的關聯.所以,幾個非常密切相關的問題:
But since I cannot add any such setter (please read my note above), I'm at a loss as to how I could force such an association. So, several very-closely-related questions:
- 誰能確認我已正確設置測試(使用 Mockito API)?
- 我對失蹤二傳手的懷疑是否正確?(我需要通過 setter 關聯這些對象嗎?)
- 如果我的上述懷疑屬實,并且我無法修改
WebAdaptor
,是否有任何規避措施可供我使用?
- Can anyone confirm that I've set the test up correctly (using the Mockito API)?
- Is my suspicion about the missing setter correct? (Do I need to associate these objects via a setter?)
- If my above suspicion is true, and I can't modify
WebAdaptor
, are there any circumventions at my dispose?
提前致謝!
推薦答案
您需要將模擬注入到您正在測試的類中.您不需要訪問訂閱者.mockito 和其他模擬框架的幫助方式是您不需要訪問正在與之交互的對象.但是,您確實需要一種將模擬對象放入您正在測試的類的方法.
You need to inject the mock into the class which you are testing. You do not need access to Subscriber. The way mockito and other mocking frameworks help is that you do not need access to objects which you are interacting with. You do however need a way to get mock objects into the class you are testing.
public class WebAdaptor {
public WebAdaptor(Subscriber subscriber) { /* Added a new constructor */
this.subscriber = subscriber;
}
private Subscriber subscriber;
public void run() {
subscriber.init();
}
}
現在您可以在模擬對象上驗證您的交互,而不是在真實對象上驗證.
Now you can verify your interactions on the mock, rather than on the real object.
@Test
public void runShouldInvokeSubscriberInit() {
// Given
Subscriber mockSubscriber = mock(Subscriber.class);
WebAdaptor adaptor = new WebAdaptor(mockSubscriber); // Use the new constructor
// When
adaptor.run();
// Then
verify(mockSubscriber).init();
}
如果將訂閱者添加到構造函數不是正確的方法,您還可以考慮使用工廠來允許 WebAdaptor 從您控制的工廠實例化新訂閱者對象.然后,您可以模擬工廠以提供模擬訂閱者.
If adding the Subscriber to the constructor is not the correct approach, you could also consider using a factory to allow WebAdaptor to instantiate new Subscriber objects from a factory which you control. You could then mock the factory to provider mock Subscribers.
這篇關于Mockito:模擬“黑盒";依賴項的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!