2017-02-21 3 views
1

Ich möchte "Quelle" verspotten, wenn die Methode "ProductAdapterService.adapt" von einer anderen Klasse aufgerufen wird.Wie man eine lokale Variable mit PowerMockito vortäuscht?

Wie geht man damit um? Ich habe wirklich viele Möglichkeiten ausprobiert. Bitte hilf mir. Ich bin ein neuer Typ. Vielen Dank!

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; 
}} 

Und unten ist mein Testcode:

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); 

}} 
+0

Wo ist Ihr Testcode? Was versuchst du zu testen? – DamCx

+0

Mock die 'getSource()' Methode auf 'SearchHit'. Ich kann nicht sehen, dass du 'hit' für irgendetwas anderes verwendest. Oder injiziere einfach die Map direkt anstelle von 'SearchHit'. –

+0

Ich füge den Test Code, bitte helfen Sie mir – mike

Antwort

0

Sie erhalten die falsche Art und Weise "spöttisch". Sie nur verwendet es, wenn Sie können nicht verwenden Sie die echte Klassenimplementierung; Sie müssen jedoch steuern, wie ein Objekt auf Methodenaufrufe reagiert.

Ihre Methode zum Test wie folgt aussieht:

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(); 

Falsch: Sie sicherstellen möchten, dass hit.getSource() verwendet wird. Weil Ihr Produktion Code verwendet wird; und Sie schreiben Ihre Komponententests Text diesen Code. Du willst also, dass dein Produktionscode seine "normale" Sache macht.

die sehr einfach Lösung hier ist also:

@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 

oder etwas ähnlich (nicht mich Nagel auf den doReturn/when Details hier)

Was können Sie hier sehen: Ihre Produktionscode braucht diese Karte, um ihren Job zu machen; Sie müssen nur sicherstellen, dass ein solches Kartenobjekt in Ihrem Produktionscode angezeigt wird.

Und falls es möglich wäre, ein real SearchHit-Objekt zu verwenden (das Sie mit einer solchen Karte konfigurieren könnten); Dann wäre das sogar besser, als dieses Objekt zu verspotten.

Sie versuchen absolut minimieren Ihre Verwendung von Mocking. Sie verwenden es nur, um die Kontrolle über Objekte zu erlangen, die während eines bestimmten Tests verwendet werden.

Und darüber hinaus: Sie sind nicht klar über den Umfang Ihrer Komponententests. Um Test diese eine Methode, Sie brauchen keine Geister. Der Unit-Test-Code, den Sie zeigen, macht im Kontext der Klasse, die Sie uns hier zeigen, keinen Sinn! Also: Gehen Sie besser zurück und schauen Sie sich genau an, "welche Einheiten ich habe" und "wie genau testen Sie diese Einheit X". Sie schreiben kein "X", indem Sie "Y" testen!

+0

Danke GhostCat. Ich verstehe, nachdem Sie das gesagt haben, stelle ich mich ein, ich habe mich geirrt. – mike

Verwandte Themen