2016-06-27 2 views
1

Я читал много сообщений за последние несколько дней, и есть некоторые, которые пытаются сделать то, что я пытаюсь выполнить, однако они относятся к классу, который расширяет класс с помощью защищенного метода , Однако у меня разные.Java Mockito: протестируйте защищенный абстрактный метод

В настоящее время у меня есть тестовый класс, который расширяет и оттачивает абстрактный класс с помощью защищенного метода. Независимо от того, как я пытаюсь реализовать значение для одного, он возвращает значение null, и я не могу понять, почему это происходит. В свою очередь это возвращает nullPointerEception, а не мое пользовательское исключение, которое должно ударить.

Мой тестовый класс следующим образом:

@RunWith(MockitoJUnitRunner.class) 
public class ServiceTest extends AbstractScraperTest<HtmlPage, List<myItems>>{ 

    @Mock private SsoSetting ssoSetting; 
    @Mock private SsoSetting.UrlSettings urlSetting; 
    // @Mock(answer = Answers.CALLS_REAL_METHODS) private ServiceForScraping serviceScrape; 
    @Mock Scraper scraper; 
    @Mock AbstractScraperTest abstractScraperTest; 
    @Mock private ProductScrape productScrape; 
    @Mock private ProductDetailScrape productDetailScrape; 

    @InjectMocks private Service service; 

    @Before 
    public void setUp() throws Exception { 
     when(ssoSetting.getUrls()).thenReturn(urlSetting); 
    } 

    final String URL = "myUrl"; 
    final ArgumentCaptor<Map> postRequestCaptor = ArgumentCaptor.forClass(Map.class); 
    final ArgumentCaptor<Scraper> scrapeCaptor = ArgumentCaptor.forClass(Scraper.class); 

    @Test(expected = customException.class) 
    public void scrape_TimeOut_Exception() throws Exception { 

    // 
    //  AbstractScraperTest ab = Mockito.mock(AbstractScraperTest.class, Mockito.CALLS_REAL_METHODS); 
    // 
    // assertEquals(ab.testScraper("htmlResource", 
    //    "myUrlToTest"), customException.class); 
    // 
    // List<productItems> result = testScraper("htmlResource","myUrlToTest"); 
    } 
} 

Абстрактный класс:

public abstract class AbstractScraperTest<Input, Output> { 
    public ServiceForScraping serviceScrape; 
    public Scraper<Input, Output> scraper; 

    protected abstract Scraper<Input, Output> getScraper(); 

    @Before 
    public void setUp() throws Exception { 
     scraper = getScraper(); 
     serviceScrape = new ServiceForScraping(); 
     ServiceForScraping .init(); 
    } 

    protected Output testScraper(String filePath, String url) throws Exception { 
     InputStream input = getClass().getResourceAsStream(filePath); 
     String html = IOUtils.toString(input); 

     return serviceScrape.scrapeString(url, html, scraper); 
    } 
} 

Тестирование класса для исключений:

public abstract class myScraper<Output> implements  HTMLUnitScraper<Output> { 

    @Override 
    public Output scrape(HtmlPage page, String scraperUrl) throws Exception { 
     checkSessionTimeout(page, scraperUrl); 
     return scrapeHtmlPage(page, scraperUrl); 
    } 

    private void checkSessionTimeout(HtmlPage page, String scraperUrl) throws Exception { 

     if (page.getFirstByXPath("//classImLookingFor']") != null 
      && page.getFirstByXPath("//ClassImLookingFor") != null) { 
      throw new customExceptionThrown("Session Timeout" + scraperUrl); 
     } 
    } 

    public abstract Output scrapeHtmlPage(HtmlPage page, String scraperUrl) throws Exception; 
} 

Тестирование абстрактных классов методом testScrape, если ресурс html содержит информацию о сеансе тайм-аута. Я использовал этот метод в других тестах, которые не используют Mockito, и все они работали:

Пример

@Test(expected=customException.class) 
    public void scrape_TimeOut_Exception() throws Exception { 
    List<CartItem> result = testScraper("htmlResource","myUrl"); 
} 

Тест должен проверить, чтобы верно, как HTML ресурс действительно содержит информацию тайм-аут сеанса.

Проблема я считаю, когда я отладки на

return serviceScrape.scrapeString(url, html, scraper); 

Скребок возвращает нуль. Я пытался делать такие вещи, как

AbstractScraperTest.scraper = scraper; 

, а также перемещение вызовов в @Before в abstractScraperTest в @Before в классе ServiceTest однако, что, кажется, не работает, как хорошо. Я не уверен, почему я возвращаю null и не могу добавить в него значение, я считаю, что именно поэтому он терпит неудачу.

Ссылки Посмотрел в том, что я помню:

  1. mocking protected method
  2. How to mock protected subclass method inherited from abstract class?
  3. How can I test a method which invoke protected (unwanted) methods of parent class?
  4. http://huahsin68.blogspot.ca/2014/01/invoke-protected-method-with.html
  5. https://groups.google.com/forum/#!topic/powermock/DtMMHa9k-4Q
  6. http://www.vogella.com/tutorials/Mockito/article.html

Я прочитал в одном сообщении, которое, как говорят, использовало PowerMockito, однако я не мог получить методы и реализации для этого.

Любая помощь, идеи, ссылки приветствуются.Я уверен, что это должно быть возможно для того, чего я пытаюсь достичь, поскольку другие довольно похожи, но я не могу понять правильную реализацию для него. Спасибо заранее, и если у вас есть какие-либо вопросы, я отвечу и могу быстро обновить сообщение.

Еще раз спасибо,

ответ

1

serviceScrape.scrapeString(url, html, scraper) возвращается нуль, так как тест вызова издеваться, и нет никакого where инструкции, поэтому поведение по умолчанию возвращается нуль.

Рассматривая прокомментированные строки, я думаю, что ваша цель состоит в том, чтобы использовать частичные mocks и вызывать реальные методы по умолчанию, не так ли? Способ сделать это:

@Mock(answer=Answers.CALLS_REAL_METHODS) private ServiceForScraping serviceScrape; 

EDIT =======

Это результат после обсуждения в комментариях. Я полностью не понял эту проблему ... Теперь я вижу, в чем проблема, и глядя на прокомментированные строки в методе scrape_TimeOut_Exception(), мой ответ таков:

Mockito предназначен для издевательства соавторов класса, который вы тестируете, а не проверить себя.

В вашем случае, вы должны просто реализовать метод getScraper() в классе ServiceTest:

@RunWith(MockitoJUnitRunner.class) 
public class ServiceTest extends AbstractScraperTest<HtmlPage, List<myItems>>{ 

    @Mock private SsoSetting ssoSetting; 
    @Mock private SsoSetting.UrlSettings urlSetting; 
    // @Mock(answer = Answers.CALLS_REAL_METHODS) private ServiceForScraping serviceScrape; 
    @Mock Scraper scraper; 
    @Mock private ProductScrape productScrape; 
    @Mock private ProductDetailScrape productDetailScrape; 

    @Before 
    public void setUp() throws Exception { 
     when(ssoSetting.getUrls()).thenReturn(urlSetting); 
    } 

    @Override 
    protected Scraper<Input, Output> getScraper() 
    { 
     return this.scraper; 
    } 

    final String URL = "myUrl"; 
    final ArgumentCaptor<Map> postRequestCaptor = ArgumentCaptor.forClass(Map.class); 
    final ArgumentCaptor<Scraper> scrapeCaptor = ArgumentCaptor.forClass(Scraper.class); 

    @Test(expected = customException.class) 
    public void scrape_TimeOut_Exception() throws Exception { 

    // TODO Mocks should be configured like SsoSetting 
    //  when(this.scraper.someMethod()).thenReturn(someOutput); 
    // ... 

     assertEquals(ab.testScraper("htmlResource", 
        "myUrlToTest"), customException.class); 

     List<productItems> result = testScraper("htmlResource","myUrlToTest"); 
    } 
} 

абстрактный класс:

public abstract class AbstractScraperTest<Input, Output> { 
    @InjectMocks public ServiceForScraping serviceScrape; 
    public Scraper<Input, Output> scraper; 

    protected abstract Scraper<Input, Output> getScraper(); 

    @Before 
    public void setUp() throws Exception { 
     scraper = getScraper(); 
     serviceScrape = new ServiceForScraping(); 
     ServiceForScraping .init(); 
    } 

    protected Output testScraper(String filePath, String url) throws Exception { 
     InputStream input = getClass().getResourceAsStream(filePath); 
     String html = IOUtils.toString(input); 

     return serviceScrape.scrapeString(url, html, scraper); 
    } 
} 

Было бы еще лучше, если абстрактный метод не используется на всех:

@RunWith(MockitoJUnitRunner.class) 
public class ServiceTest extends AbstractScraperTest<HtmlPage, List<myItems>>{ 

    @Mock private SsoSetting ssoSetting; 
    @Mock private SsoSetting.UrlSettings urlSetting; 
    // @Mock(answer = Answers.CALLS_REAL_METHODS) private ServiceForScraping serviceScrape; 
    // use the one from the super @Mock Scraper scraper; 
    @Mock private ProductScrape productScrape; 
    @Mock private ProductDetailScrape productDetailScrape; 

    @Before 
    public void setUp() throws Exception { 
     when(ssoSetting.getUrls()).thenReturn(urlSetting); 
    } 

    final String URL = "myUrl"; 
    final ArgumentCaptor<Map> postRequestCaptor = ArgumentCaptor.forClass(Map.class); 
    final ArgumentCaptor<Scraper> scrapeCaptor = ArgumentCaptor.forClass(Scraper.class); 

    @Test(expected = customException.class) 
    public void scrape_TimeOut_Exception() throws Exception { 

    // TODO Mocks should be configured like SsoSetting 
    //  when(super.scraper.someMethod()).thenReturn(someOutput); 
    // maybe set something in the tested instance: 
    // super.serviceScrape.setSomething(this.something); 
    // ... 

     assertEquals(ab.testScraper("htmlResource", 
        "myUrlToTest"), customException.class); 

     List<productItems> result = testScraper("htmlResource","myUrlToTest"); 
    } 
} 

аннотация класс:

public abstract class AbstractScraperTest<Input, Output> { 
    @InjectMocks public ServiceForScraping serviceScrape; 
    @Mock public Scraper<Input, Output> scraper; 

    @Before 
    public void setUp() throws Exception { 
     serviceScrape = new ServiceForScraping(); 
     ServiceForScraping .init(); 
    } 

    protected Output testScraper(String filePath, String url) throws Exception { 
     InputStream input = getClass().getResourceAsStream(filePath); 
     String html = IOUtils.toString(input); 

     return serviceScrape.scrapeString(url, html, scraper); 
    } 
} 

Обратите внимание, что в этом случае, каждый тест расширяя абстрактный класс может настроить все издевается (также наследуемые из них) по мере необходимости.

Надеюсь, это поможет и извините за мое недоразумение!

+0

Итак, я попробовал добавить частичный макет (который я не совсем уверен, что он делает), и он по-прежнему возвращает null. Возможно, я внедряю это неправильно? Я обновил сообщение с вами. Цените помощь, кстати. – L1ghtk3ira

+1

Также я прочитал это сообщение http://stackoverflow.com/questions/33516324/difference-between-mockito-spy-and-mockanswer-answers-calls-real-methods, и ответ говорит, что это добавление, которое вы предложили, небезопасно в синтаксисе. – L1ghtk3ira

+0

Действительно! Тем не менее, ваша цель не ясна для меня. Используя mockito, у вас должен быть один реальный экземпляр, который вы тестируете, и макеты для классов соавторов. Является ли реальным экземпляром, который вы тестируете, объявленным в абстрактном классе, ServiceForScraping serviceScrape? –

Смежные вопросы