Issue
Is it possible to test methods of serviceA and tell the test environment to replace all calls from serviceA to serviceB with a mockServiceB?
This is the method I´d like to test (ServiceA.java
):
@Inject
ServiceB serviceB;
public boolean tokenExists(ItemModel item) throws Exception {
try {
List<ItemModel > items = serviceB.getItems();
String token = item.getToken();
return items.stream().filter(i -> i.getToken().equals(token)).findFirst().isPresent();
} catch (ApiException e) {
throw new Exception(500, "Data could not be fetched.", e);
}
}
Since serviceB.getItems()
will result in a REST-call, I'd like to replace calls to serviceB
with a custom mockServiceB
where I just load mock data from a json file like this (TestServiceA.java
):
@InjectMock
ServiceB serviceB;
@ApplicationScoped
public static class ServiceB {
private ObjectMapper objMapper = new ObjectMapper();;
public List<ItemModel> getItems() throws IOException {
final String itemsAsJson;
try {
itemsAsJson= IOUtils.toString(new FileReader(RESOURCE_PATH + "items.json"));
objMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
List<Item> items= objMapper.readValue(itemsAsJson, objMapper.getTypeFactory().constructCollectionType(List.class, ItemModel.class));
return items;
} catch (IOException e) {
throw e;
}
}
}
And then test the tokenExists
method like this (TestServiceA.java
):
@Test
public void testTokenExists() {
try {
Assertions.assertTrue(this.serviceA.tokenExists(this.getTestItem()));
} catch (Exception e) {
fail("exception");
}
}
However, when I run the test testTokenExists
it still calls the original serviceB.getItems()
. So my question would be if this is even possible or if I have to take a different approach.
Solution
You need to mock the serviceB
inside ServiceA
class, you have two different options:
First
You can use whitebox
or reflection
and assign the mocked the serviceB
to ServiceA
class
public class TestExample {
@Mock
private ServiceB mockedServiceB;
private ServiceA serviceA;
@Before
public void setUp() {
serviceA = new ServiceA();
}
@Test
public void shouldDoSomething() {
// Arrange
Whitebox.setInternalState(serviceA, "serviceB", mockedServiceB);
when(serviceB.getItems()).thenReturn(list);
// Act & Assert
Assertions.assertTrue(serviceA.tokenExists(this.getTestItem()));
}
}
Second
You can use @InjectMocks
public class TestExample {
@Mock
private ServiceB mockedServiceB;
@InjectMocks
private ServiceA serviceA;
@Before
public void setUp() {
serviceA = new ServiceA();
}
@Test
public void shouldDoSomething() {
// Arrange
List<Item> list = new ArrayList<>();
list.add(new Item(...)); // add whatever you want to the list
when(serviceB.getItems()).thenReturn(list);
// Act & Assert
Assertions.assertTrue(serviceA.tokenExists(this.getTestItem()));
}
}
Note: prepare your runner also
Answered By - heaprc
Answer Checked By - Terry (JavaFixing Volunteer)