0

Am writting test class for my service implementation class. That service impl class having communication with my repository interface for DB action.

Code is working properly, but while i was writting the test cases for this implementation and getting "wanter but not invoked" error from junit.

Please find my classes below.

Following is my Repository interface

public interface UserRepository extends JpaSpecificationExecutor<UserDeactivationThreshold>,CrudRepository<UserDeactivationThreshold,Long> {

    @Query("SELECT bt from BusinessTypes bt where bt.code = :businessTypeCode")
    BusinessTypes findByBusinessCodeId(@Param("businessTypeCode") String businessTypeCode); 
    }

Following is my Service interface

public interface UserDeactivationThresholdService {

    public List<UserDeactivationThreshold> getThresholdValue(String businessTypeName);
}

Following is my Service Implementation class

@Service
@Transactional(readOnly = true)
public class UserDeactivationThresholdServiceImpl implements UserDeactivationThresholdService {

    private UserRepository userRepository;


    @Autowired
    public UserDeactivationThresholdServiceImpl(UserRepository userRepository,SecurityClient securityClient, EmailDispatcherService emailDispatcherService) {
        this.userRepository = userRepository;

    }


    @Override
    public List<UserDeactivationThreshold> getThresholdValue(String businessTypeName){
        return userRepository.findByBusinessType(businessTypeName);
    }
}

Please find my Test class

@RunWith(MockitoJUnitRunner.class)
public class UserDeactivationThresholdServiceImplTest {

    @Mock
    private UserRepository userRepository;

    @Mock private UserDeactivationThresholdServiceImpl userDeactivationThresholdServiceImpl;

    @Test
    public void shouldGetThresholdValueTest() {
        UserDeactivationThreshold userDeactivationThreshold = make(a(UserDeactivationThresholdMaker.BCP));
        when(userRepository.findByBusinessType("BCP")).thenReturn(asList(userDeactivationThreshold));

        verify(userRepository, times(1)).findByBusinessType("BCP");
    }
}

Following errors that am getting :

Wanted but not invoked:
userDeactivationThresholdRepository.findByBusinessType(
    "BCP"
);
-> at com.core.service.impl.UserDeactivationThresholdServiceImplTest.shouldGetThresholdValueTest(UserDeactivationThresholdServiceImplTest.java:58)
Actually, there were zero interactions with this mock.

* Update *

I tried in this way also, but that also not worked.

verify(userDeactivationThresholdServiceImpl, times(1)).getThresholdValue("BCP");

Following error that i was getting.

-> at com.core.service.impl.UserDeactivationThresholdServiceImplTest.shouldGetThresholdValueTest(UserDeactivationThresholdServiceImplTest.java:58)
Actually, there were zero interactions with this mock.

* Update 2 *

I have added the below code in to my test class. But now am getting the different issue "The method is(Integer) is ambiguous for the type UserDeactivationThresholdServiceImplTest"

    List<UserDeactivationThreshold> userDeactivationThresholdList = userDeactivationThresholdServiceImpl.getThresholdValue("BCP");
    assertThat(userDeactivationThresholdList.size(), is(1));

Am getting the below messiage for is(1).

The method is(Integer) is ambiguous for the type UserDeactivationThresholdServiceImplTest
Karthikeyan
  • 93
  • 3
  • 14
  • 2
    where do you invoke getThresholdValue method in test? – Maciej Kowalski Aug 04 '19 at 08:18
  • @MaciejKowalski - i tried by calling the `getThresholdValue()` method. that time was getting `Actually, there were zero interactions with this mock.`. Updated in my question also. – Karthikeyan Aug 04 '19 at 08:26
  • The error message is pretty unambiguous: the mock did not get invoked. You wanted the mock to get invoked. Therefore, the test failed. The root cause is that you wire your mock, but do not call the system under test. – Turing85 Aug 04 '19 at 08:27
  • Often using `verify` in this way is a bit of a code smell. For me it is better used to insure a side effect free method has been called. Just my thoughts, I suspect few agree :) – Gavin Aug 04 '19 at 08:28
  • 2
    You're completely missing the point of testing. Your class is named UserDeactivationThresholdServiceImplTest. Given this name, it's supposed to test if the code of the class UserDeactivationThresholdServiceImpl is doing what it should do. So the test should **use**, i.e. **call methods** of this class. But it doesn't. So, what are you testing here? Nothing, except Mockito. – JB Nizet Aug 04 '19 at 08:30
  • @Gavin why would you only test side-effect free calls? Following your argumentation, how would you test that e.g. a `DAO` calls an `EntityManager`? Or that a `Controller` calls a `Service`? – Turing85 Aug 04 '19 at 08:32
  • @Turing85 I suspect Gavin meant the reverse: verify is useful when testing that side-effect-ful methods have been called. In this case, just testing that the service returns what the repository has been stubbed to return is sufficient. verify() is redundant: the service can't possibly get what ir returns fom nowhere. – JB Nizet Aug 04 '19 at 08:38
  • so, this is not sufficient enough `verify(userDeactivationThresholdServiceImpl, times(1)).getThresholdValue("BCP");` to complete the test. Am new to Junit/Mockito. If i get the solution. it will be more helpful for me. – Karthikeyan Aug 04 '19 at 08:42
  • @Karthikeyan "*If i get the solution. it will be more helpful for me.*" - There are plenty of tutorials on JUnit and Mockito out there. I do not see how us providing a ready-to-use solution to your problem would improve your understanding of JUnit and/or Mockito. – Turing85 Aug 04 '19 at 08:46
  • @Turing85 what I meant was that often `when` is sufficient to test that a mocked method is called as if the method isint called you are unlikely to get the result you expected. I find `verify` useful when you want to verify that a call is made, but dont want or need to mock a response, I often find this pattern when working with repositories. I hope that clarifies. – Gavin Aug 04 '19 at 09:11
  • 2
    @Karthikeyan in your first attempt, you don't even use the class under test. In the second attempt, you mock the class under test, thus replacing the code that you want to test by mocked code. Again: to test some code, you need to execute that code. Don't mock the class under test. Mock its dependencies. Read this for a detailed explanation: https://stackoverflow.com/a/28783849/571407 – JB Nizet Aug 04 '19 at 09:50

1 Answers1

2

As others pointed out already you made the usual beginner mistakes:

  • Do not mock the class under test.
  • Make sure that your mocks are injected into your class under test, either by using annotations (@Mock, @InjectMocks) or by providing the references to the mock manually to the class under test.
  • Use the instance of your class under test in the test to actually test something.

Make sure to read the documentation and a tutorial (e.g. this, this or this) again. There are also plenty of similiar question to be found here with answers that provide some code examples as well.

Turing85
  • 18,217
  • 7
  • 33
  • 58
second
  • 4,069
  • 2
  • 9
  • 24
  • Thanks., i have added `assertThat()` method and now am facing `The method is(Integer) is ambiguous for the type UserDeactivationThresholdServiceImplTest` issue. I have updated the details in Question. – Karthikeyan Aug 04 '19 at 10:21
  • Why not simply use `assertEquals` instead? (The ambiguity might come from mixing imports) – second Aug 04 '19 at 10:28