Issue
I am performing a unit test for addPortfolioTrans method below. But not sure how do i mock the method validateSellAction(portfolioTrans) without mocking PortfolioTransServiceImpl class.
PortfolioTransServiceImpl class:
@Override
public PortfolioTrans addPortfolioTrans(PortfolioTrans portfolioTrans, long portId, String username) {
if (portfolioTrans.getAction().equals(ConstantUtil.SELL_ACTION)) {
sellActionCheck = validateSellAction(portfolioTrans);
}
}
I wanted to do something like this below for my test class. But I am not sure how to do it without mocking an object. My objective is to return a -1 value after mocking the validateSellAction method.
TestPortfolioTransServiceImp class:
@InjectMocks
@Autowired
private PortfolioTransServiceImpl portfolioTransServiceImpl;
@Test
void testAddPortfolioTrans_sellSuccess() {
Long portId = 2L;
String username = "user1";
PortfolioTrans portfolioTransObj = new PortfolioTrans();
portfolioTransObj.setStockName("Microsoft Corp.");
portfolioTransObj.setAction("SELL");
portfolioTransObj.setNoOfShare(50);
portfolioTransObj.setStockSymbol("MSFT");
portfolioTransObj.setStockExchg("NASDAQ");
portfolioTransObj.setTransPrice(new BigDecimal("269.81"));
PortfolioTrans result = portfolioTransServiceImpl.addPortfolioTrans(portfolioTransObj, 0, username);
//wanted to mock return value below, but not sure how to do it without mocking object
when(validateSellAction(portfolioTrans)).thenReturn(-1);
//assert statements below
}
Solution
What you're looking for can be achieved by "spying" on an object - creating a spy object based on an actual object instance (thanks to @Jeff Bowman for the clarifying comment). It allows you to verify calls to certain methods, but also partially redefine the object's behaviour, for example mocking a single method, while preserving behaviour of all the others. You can read about Mockito spies in the docs or many other sources on the Internet.
What you have to do is either annotate the field with a @Spy
annotation, call the spy(...)
method explicitly or use a @SpyBean
annotation, if you're using Spring (which I assume might be the case, since there's @Autowired
over a field).
The approach is called partial mocking. You can also use mocks and tell Mockito to call actual methods implementation instead of mocking all the rest (by using doCallRealMethod or thenCallRealMethod
described in the docs link above).
Answered By - Jonasz
Answer Checked By - Terry (JavaFixing Volunteer)