Krishna
Krishna

Reputation: 549

Mockito - Mock a method inside async method that is under test

Hi I am trying to do some unit tests with async methods. below is my code. the first line of methodUnderTest() where I mocked the doWork is returning null during execution and test fails. I tried different things related to async but nothing worked. What am I missing here.

 public class AServiceImpl{
   @Autowired
   BService bService;

   @Async
   public CompletableFuture<String> methodUnderTest(String input){
     String s = bService.doWork(input.substring(3));
     //blah blah blah
     return CompletableFuture.completedFuture(s);
   }
}


public class AServiceTest{
  private BService bService;
  private AService aService;
  @Before
  void beforeTest(){
     aService = new AServiceImpl();
     bService = mock(BService.class);
     //blah blah blah
  }

  @Test
  public void someUnitTest(){
     Mockito.when(bService.doWork(any())).thenReturn("ABC");
     String s = aService.methodUnderTest("ABCDEF").get();
     Assert.assertNotNull(s);
  }
}

Upvotes: 2

Views: 956

Answers (2)

Rangi Keen
Rangi Keen

Reputation: 945

Your auto wiring will only work in the production code. You need to manually inject your mock BService in your test.

@Before
void beforeTest() {
    aService = new AServiceImpl();
    bService = mock(BService.class);
    aService.bService = bService;
    ...
}

You may be able to run your tests with spring to inject test dependencies using @RunWith(SpringRunner.class) (JUnit 4) or @ExtendWith(SpringExtension.class) (Junit 5).

Upvotes: 0

Nkosi
Nkosi

Reputation: 247153

Nothing to do with @Async here. The mock setup in the test is not being assigned to the subject under test.

First I would suggest avoiding Autowired fields and having your class explicitly expose their dependencies via constructor dependencies

public class AServiceImpl {
    
    private final BService bService;

    @Autowired
    public AServiceImpl(BService bService) {
        this.bService = bService;
    }

    @Async
    public CompletableFuture<String> methodUnderTest(String input) {
        String s = bService.doWork(input.substring(3));

        //...

        return CompletableFuture.completedFuture(s);
    }
}

And then explicitly inject the dependency when testing

public class AServiceTest{
    private BService bService;
    private AService aService;

    @Before
    void beforeTest() {
        bService = mock(BService.class);
        aService = new AServiceImpl(bService); //<-- injecting mocked dependency

        //...
    }

    @Test
    public void someUnitTest(){
        // Arrange
        Mockito.when(bService.doWork(any())).thenReturn("ABC");
        // Act
        String s = aService.methodUnderTest("ABCDEF").get();
        // Assert
        Assert.assertNotNull(s);
    }
}

Upvotes: 1

Related Questions