1

This is my main code:

@Service
public class MainService {
    public String mainMethod() {
        SomeService someService = new SomeService("required");
        // do Sth.
    }
}

@Service
@RequiredArgsConstructor
public class SomeService {
    @Autowired
    private SomeOtherService someOtherService;
    @Notnull
    private final String requiredField;
    // ...
}

@Service
public class SomeOtherService {
    // just a bunch of public methods that might as well be static
}

And this is the test setup:

@RunWith(SpringRunner.class)
public class MainServiceTest {
    @InjectMocks
    private MainService mainService;

    @Test
    public void givenSth_whenSth_doSth() {
        // test mainService.mainMethod();
    }
}

Can you please tell me why someOtherService inside SomeService is null?

I figured out when yo use Spring's injection, you should not use manual instantiation (new ...) at the same time; so maybe new SomeService("required") is the problem? But then how do I inject field variables into SomeService if not by constructor call? I don't want to use the Builder because requiredField is supposed to be NotNull.

Phil
  • 7,065
  • 8
  • 49
  • 91
  • Yes this is a duplicate, but finally this answer helped me more than the one suggested by @M.Deinum: https://stackoverflow.com/a/29599822/4125622 I also came to realize it is not possible to mock a service used by a mocked service. In a unit test only one layer of the blackboxed outside world should be mocked anyway. – Phil Oct 15 '18 at 08:43
  • Now I am using @InjectMocks for the Service I want to test and @Mock and Mockito.mock(SubService.class); for the services it uses. I don't do @Autowire for those second level services anymore and manually adjust what is returned by `Mockito.when(subService.doSth()).thenReturn("foo bar");` – Phil Oct 15 '18 at 08:47

2 Answers2

0

You can follow Adam Weidner's tutorial using MockBean for Spring Bean and extending AbstractTestNGSpringContextTest for TestNG with Spring

@TestExecutionListeners(MockitoTestExecutionListener.class)
@SpringBootTest
public class WidgetServiceIntegrationTest extends AbstractTestNGSpringContextTest {
@MockBean private SprockService sprockService;
@MockBean private SpringService springService;
@Autowired WidgetService widgetService;
@Test
public void testSomethingOnWidgetService() {
     when(sprockService.makeASprock()).thenReturn(...);
Ori Marko
  • 56,308
  • 23
  • 131
  • 233
  • But I don't want to mock the @Autowired class. The test is supposed to use the original. In integration tests this is valid. Besides, testing with AbstractTestNGSpringContextTest seems to be kind of rare. On google I find barely any results for this. – Phil Oct 14 '18 at 10:17
  • I am using Mockito only for mocking requiredField. In my real application it is not type String but a domain object – Phil Oct 14 '18 at 10:24
  • @Phil Do you mean https://stackoverflow.com/questions/41570821/spring-how-to-inject-a-string-bean-to-the-constructor ? – Ori Marko Oct 14 '18 at 10:32
  • maybe, I am trying to figure out if lombok's RequiredArgsConstructor is setting things up the wrong way (not like in that response) in my code. I will check on that a bit more now. thank you – Phil Oct 14 '18 at 10:57
0

For integration testing consider instantiating bean using context configuration like below

@RunWith(SpringRunner.class)
@ContextConfiguration("mockito-config.xml")

For a detailed explanation, please refer

For unit testing, Please consider using @Mock annotation provided by Mockito.

In this specific example, We could mock SomeOtherService as shown below

 @RunWith(SpringRunner.class)
 public class MainServiceTest {

 @InjectMocks
 private MainService mainService;

 @Mock
 private SomeOtherService someOtherService

 @Test
 public void givenSth_whenSth_doSth() {
     // test mainService.mainMethod();
 }
}

For a detailed explanation please refer the following post

Vinoth A
  • 1,099
  • 9
  • 10
  • Thank you for your reply. But someOtherService is not used inside MainServiceTest. It is used only in SomeService. I tried to make an unused someOtherService variable in the Test-class, but the result is the same. – Phil Oct 14 '18 at 10:30