如何使用 PowerMockito 模拟局部变量?
How to mock a local variable with PowerMockito?
我想在方法 "ProductAdapterService.adapt" 被其他 class 调用时模拟 "source"。
如何处理?我真的尝试了很多方法。请帮我。我是新人guy.Thanks很多!
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;
}}
下面是我的测试代码:
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);
}}
您 "mocking" 的理解方式有误。当您 不能 使用真正的 class 实现时,您 仅 使用它;但您需要控制某些对象如何对调用它的方法做出反应。
您的测试方法如下:
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();
错误:您想要确保使用hit.getSource()
。因为您的 production 代码使用的是;然后将单元测试编写到 text 该代码。所以你希望你的生产代码做它的 "normal" 事情。
所以,这里非常简单的解决方案是:
@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
或类似的东西(不要在这里强调 doReturn/when 细节)
您在这里可以看到:您的生产代码需要该映射来完成它的工作;所以你只需确保这样的地图对象出现在你的生产代码中。
如果可以使用 真实 SearchHit 对象(您可以使用这样的地图进行配置);然后使用它甚至比模拟那个对象更好。
你一定要尽量尽量减少你对模拟的使用。您仅使用它来控制在特定测试期间使用的对象。
除此之外:您不清楚单元测试的范围。为了测试那个方法,你不需要鬼魂。您展示的单元测试代码在 class 的上下文中根本没有意义!因此:你最好退后一步,仔细研究 "which units do I have" 和 "how to unit test exactly that unit X"。您不会通过测试 "Y"!
发短信给 "X"
我想在方法 "ProductAdapterService.adapt" 被其他 class 调用时模拟 "source"。
如何处理?我真的尝试了很多方法。请帮我。我是新人guy.Thanks很多!
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;
}}
下面是我的测试代码:
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);
}}
您 "mocking" 的理解方式有误。当您 不能 使用真正的 class 实现时,您 仅 使用它;但您需要控制某些对象如何对调用它的方法做出反应。
您的测试方法如下:
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();
错误:您想要确保使用hit.getSource()
。因为您的 production 代码使用的是;然后将单元测试编写到 text 该代码。所以你希望你的生产代码做它的 "normal" 事情。
所以,这里非常简单的解决方案是:
@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
或类似的东西(不要在这里强调 doReturn/when 细节)
您在这里可以看到:您的生产代码需要该映射来完成它的工作;所以你只需确保这样的地图对象出现在你的生产代码中。
如果可以使用 真实 SearchHit 对象(您可以使用这样的地图进行配置);然后使用它甚至比模拟那个对象更好。
你一定要尽量尽量减少你对模拟的使用。您仅使用它来控制在特定测试期间使用的对象。
除此之外:您不清楚单元测试的范围。为了测试那个方法,你不需要鬼魂。您展示的单元测试代码在 class 的上下文中根本没有意义!因此:你最好退后一步,仔细研究 "which units do I have" 和 "how to unit test exactly that unit X"。您不会通过测试 "Y"!
发短信给 "X"