简体   繁体   中英

Mockito - Invalid use of Matchers Exception

I am getting Invalid use of matchers Exception when i use the below statement. Mockito.when(CrossSellOffersRetrievalService.isHourInInterval(Mockito.anyString(), Mockito.anyString(), Mockito.anyString())).thenReturn(true);

How to avoid this exception?

class:

@Component
public class CrossSellOffersRetrievalService {

    @Autowired
    private CrossSellOffersRetrieval crossSellOffersRetrieval;

    public List<CrossSellOffer> getApplicableOffers(String channelId, String customerId, String cinSuffix, String countryCode,
            String interactionPoint, String sessionId, Integer numberOfOffers)throws CrossSellOffersException {

        if (isOnLineServerTime()) {
            if (numberOfOffers == null) {
                numberOfOffers = 1;
            }
            List<CrossSellOffer> crossSellOffersList = crossSellOffersRetrieval.getApplicableOffers(channelId, customerId, cinSuffix,
                            countryCode, interactionPoint, sessionId,numberOfOffers);

                return crossSellOffersList;

        } else {
            throw new CrossSellOffersException(Constants.ERROR_CODE, Constants.WRONG_SERVER_TIME);
        }
    }

    public static boolean isHourInInterval(String target, String start, String end) {
        return ((target.compareTo(start) >= 0) && (target.compareTo(end) <= 0));
    }

    public boolean isOnLineServerTime() {

        String serverTime = DateTimeFormatter.ofPattern("HH.mm").format(LocalDateTime.now(ZoneId.of("Asia/Singapore")));

        boolean value = isHourInInterval(serverTime,"08.00","23.15");
        return value;
    }

}

Junit test class:

@RunWith(MockitoJUnitRunner.class)
public class CrossSellOffersRetrievalServiceTest {

    @InjectMocks
    private CrossSellOffersRetrievalService crossSellOffersRetrievalService;

    @Mock
    private CrossSellOffersRetrieval crossSellOffersRetrieval;

    @Test
    public void getApplicableOffersTest() throws CrossSellOffersException {
        Mockito.when(CrossSellOffersRetrievalService.isHourInInterval(Mockito.anyString(), Mockito.anyString(), Mockito.anyString())).thenReturn(true);
        Mockito.when(crossSellOffersRetrieval.getApplicableOffers(Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), 1)).thenReturn(CrossSellOffersRetrievalHandlerTest.sampleCrossSellOffersList());
        List<CrossSellOffer> crossSellOffersList = crossSellOffersRetrievalService.getApplicableOffers("MBSG", "S7754061Z", "00", "SG", "NEW_CC_ADDON", "IBOXS007", 1);
    }
}

output:

org.mockito.exceptions.misusing.InvalidUseOfMatchersException: 
Misplaced or misused argument matcher detected here:

-> at com.dbs.crossselloffers.offers_retrieval.CrossSellOffersRetrievalServiceTest.getApplicableOffersTest(CrossSellOffersRetrievalServiceTest.java:12)
-> at com.dbs.crossselloffers.offers_retrieval.CrossSellOffersRetrievalServiceTest.getApplicableOffersTest(CrossSellOffersRetrievalServiceTest.java:12)
-> at com.dbs.crossselloffers.offers_retrieval.CrossSellOffersRetrievalServiceTest.getApplicableOffersTest(CrossSellOffersRetrievalServiceTest.java:12)

You cannot use argument matchers outside of verification or stubbing.
Examples of correct usage of argument matchers:
    when(mock.get(anyInt())).thenReturn(null);
    doThrow(new RuntimeException()).when(mock).someVoidMethod(anyObject());
    verify(mock).someMethod(contains("foo"))

You cannot use argument matchers outside of verification or stubbing.

Your CrossSellOffersRetrievalService is not mocked. It is an actual instance of CrossSellOffersRetrievalService , instantiated with mocks. See the @InjectMocks documentation .

Therefore, you're trying to stub something which is not a mock. Consider mocking or partially mocking it, if you don't want to call the actual isHourInInterval() method. To do this, you'd probably want to make the method non-static. You can mock a static method but it's often not the best thing to do.


An additional note:

Since CrossSellOffersRetrievalService is what you're testing , you probably don't want to mock or partial mock it - since if you do, you're not testing its real functionality. In addition, you probably do want to check that your output is what you expect it to be, not just that you can call the class' methods.

You could spy on an actual instance of CrossSellOffersRetrievalService , but I'd suggest writing simple tests, eg for a method:

  1. Have an input.
  2. Use your injected mocks and when... thenReturn to handle mock calls in the method.
  3. Define your expected output.
  4. Call the method with the input.
  5. Verify that the actual output equals the expected output.

Repeat for all important cases for each method, until each method is covered.

If this method is difficult for your class, consider changing the class. For example, if it's a pain to mock or build input to satisfy isHourInInterval , encapsulate that method inside a separate object, which you inject into your CrossSellOffersRetrievalService . You can even make it a static inner class, if it's really not relevant to anything else. Then, when testing, inject a mock that always returns true.

You're trying to stub a static method. Mockito doesn't do that.

You've also got an error on the following line, where you've got a mixture of matcher and non-matcher arguments to a stubbing call (you'll need to change 1 to eq(1) ).

Anyway, looking at the class you're trying to test, it looks like it behaves differently at different times of the day. So you're probably going to want tests for its behaviour between 8:00 and 23:15, and other tests for how it behaves outside those hours.

You're going to need the Clock class to set up tests like that. There's some information about how to do that at Unit testing a class with a Java 8 Clock

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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