I am performing a unit test for addPortfolioTrans
method below. But I'm 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) {
StockWrapper stockWrapper = portfolioHoldService.findStock(stockSym);
if ((stockWrapper.getStock() == null || stockWrapper.getStock().getQuote().getPrice() == null)) {
portfolioTrans.setErrMsg("Stock Symbol is invalid, unable to get stock price. Save transaction failed.");
return portfolioTrans;
}
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;
@Mock
PortfolioHoldService portfolioHoldService;
@Test
void testAddPortfolioTrans_sellSuccess() {
Long portId = 2L;
String username = "user1";
//edited and added this portion
Stock stock = new Stock("MSFT");
stock.setStockExchange("NasdaqGS");
stock.setName("Microsoft Corp.");
StockQuote stockQuote = new StockQuote("MSFT");
stockQuote.setPrice(new BigDecimal("280.04"));
stock.setQuote(stockQuote);
StockWrapper dummyStockWrapper = new StockWrapper(stock);
//i have other dependencies with other services
when(portfolioHoldService.findStock(anyString())).thenReturn(dummyStockWrapper);
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
}
CodePudding user response:
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).