简体   繁体   English

如何使用PowerMockito模拟局部变量?

[英]How to mock a local variable with PowerMockito?

I want to mock "source" when the method "ProductAdapterService.adapt" is called by other class. 当其他类调用方法“ProductAdapterService.adapt”时,我想模拟“source”。

How to deal that? 怎么处理? I really tried a lot of ways. 我真的尝试了很多方法。 Please help me. 请帮我。 I am a new guy.Thanks a lot! 我是一个新人。非常感谢!

    public class ProductAdapterService {
private final SearchParameter parameter;
private List<Festival> festivals;

public ProductAdapterService(SearchParameter parameter) {
    this.parameter = parameter;
}

public SingleProduct adapt(SearchHit hit, boolean bidding) {

    //I want to mock "source", I don't want to use "hit.getSource()"
    Map<String, Object> source = hit.getSource();

    SingleProduct sp = new SingleProduct();
    sp.setId(TypeConverter.toInt(source.get(FieldName.PRODUCT_ID)));
    sp.setName(TypeConverter.toString(source.get(FieldName.NAME)));
    sp.setPrice(this.price(source.get(FieldName.PRICE), source.get(FieldName.PRICE_MAP), source.get(FieldName.FIRST_START_CITIES)));
    sp.setLevel(TypeConverter.toInt(source.get(FieldName.PRODUCT_LEVEL)));
    sp.setDepartureCityId(this.departureCity(source.get(FieldName.DEPARTURE_CITY_ID), source.get(FieldName.FIRST_START_CITIES)));
    sp.setSaleMode(TypeConverter.toString(source.get(FieldName.SALE_MODE)));
    sp.setBrandName(this.providerBrandName(source.get(FieldName.PROVIDER_BRAND)));
    sp.setSaleCount(TypeConverter.toInt(source.get(FieldName.MONTHLY_ORDER)));
    sp.setCommentCount(TypeConverter.toInt(source.get(FieldName.COMMENT_COUNT)));
    sp.setCommentScore(TypeConverter.toFloat(source.get(FieldName.COMMENT_SCORE)));
    sp.setBuType(BuType.GT);
    sp.setType(this.productType(source.get(FieldName.SEARCH_TAB_TYPE_SHOW), sp.getSaleMode()));
    sp.setSaleout(this.saleout(source.get(FieldName.NON_SALEOUT_CITIES), sp.getDepartureCityId()));
    if (!sp.isSaleout()) {
        sp.setFestival(this.festival(source.get(FieldName.FESTIVAL_IDS)));
    }
    System.out.println("sp.getName(): " + sp.getName());
    return sp;
}}

And below is my test code: 以下是我的测试代码:

public class TabSearcherTest0 {

@Test
public void test() {
    SearchParameter parameter = SearchParameter.create();
    Ghost.begin();
    parameter.getFiltered().setTab(TabType.ALL);
    parameter.getPoi().setKeyword("Spa");
    parameter.getClient().setTrace(TraceMode.MAIN);

    Map<String, Object> mapMock = new HashMap<String, Object>();
    mapMock.put("productgroupid", "12877");
    mapMock.put("productid", "5539739");
    mapMock.put("firststartcitys", "[1, 2]");
    mapMock.put("nonsaleoutcities", "[1, 2]");
    mapMock.put("productdiamondlevel", "4");
    mapMock.put("commentcount", "0");
    mapMock.put("price", "0.0");
    mapMock.put("name", "TestName");
    mapMock.put("searchtabtypeshow", "1");
    mapMock.put("comment", "0.0");
    mapMock.put("salemode", "S");
    mapMock.put("providerbrandid", "999999");
    mapMock.put("departurecityid", "2");

    // how to inject the map?
    // ???

    SearchModel model = SearchContext.createContext(parameter).search();
    Ghost.end();
    System.out.println(model);

}}

You are getting "mocking" the wrong way. 你正在“嘲弄”错误的方式。 You only used it when you can not use the real class implementation; 不能使用真实类实现时才使用它; but you need to control how some object reacts to methods calls to it. 但是你需要控制一些对象对方法调用的反应。

Your method to test looks like: 您的测试方法如下:

public SingleProduct adapt(SearchHit hit, boolean bidding) {
  //I want to mock "source", I don't want to use "hit.getSource()"
  Map<String, Object> source = hit.getSource();

Wrong: you want to make sure that hit.getSource() is used. 错误:您确保使用hit.getSource() Because your production code is using is; 因为您的生产代码正在使用; and you write your unit tests to text that code. 并且您将单元测试写入文本代码。 So you want that your production code does its "normal" thing. 所以你希望你的生产代码做“正常”的事情。

So, the very simply solution here is: 所以,这里非常简单的解决方案是:

 @Test
 public void testAdapt() {
   SearchHit mockedHit = mock(SearchHit.class);

   Map<String, Object> resonseForGetSource = new HashMap<>();
   resonseForGetSource.put("productgroupid", "12877"); 
   ...

   doReturn(resonseForGetSource).when(mockedHit.getSource());

   ProductAdapterService underTest = ...
   underTest.adapt(mockedHit, true);
   ... probably some asserts

or something alike (don't nail me on the doReturn/when details here) 或类似的东西(不要在doReturn上钉我/这里的细节)

What you can see here: your production code needs that map to do its job; 您可以在此处看到:您的生产代码需要该地图来完成其工作; so you just make sure that such a map object shows up in your production code. 所以你只需要确保这样的地图对象出现在你的生产代码中。

And in case it would be possible to use a real SearchHit object (that you could configure with such a map); 如果可以使用真正的 SearchHit对象(您可以使用这样的地图进行配置); then using that would even be better than mocking that object. 然后使用它甚至比嘲笑那个对象更好。

You absolutely try to minimize your usage of mocking. 你绝对试着尽量减少你对模拟的使用。 You only use it to gain control over objects that are used during a certain test. 您只能使用它来控制在特定测试期间使用的对象。

And beyond that: you are not clear about the scope of your unit testing. 除此之外:您不清楚单元测试的范围。 In order to test that one method, you dont need no ghosts. 为了测试那种方法,你不需要鬼。 The unit test code you are showing simply doesn't make sense in the context of the class you are showing us here! 您所展示的单元测试代码在您向我们展示的课程中没有任何意义! Thus: you better step back and carefully look into "which units do I have" and "how to unit test exactly that unit X". 因此:你最好退后一步,仔细研究“我有哪些单位”和“如何准确测试单位X”。 You don't text "X" by testing "Y"! 你不要通过测试“Y”来发短信“X”!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM