I am working on a basic test-driven development learning of a simple java program which provides portfolio value for the stocks.
I am having 2 classes,Portfolio.java
& Stock.java
which depicts the portfolio & stock models. An interface StockService.java
is used in abstract manner to get real-time stock price.
PortfolioTest.java
is the class in which I am trying to write unit-tests for the features of portfolio by mocking this StockService using Mockito.
I am able to use the deprecated MockitoAnnotations.initMocks(this);
& run my tests but getting null pointer exception if try to use @Rule
or @RunWith
annotations.
Stock.java
public class Stock {
private String name;
private int quantity;
public Stock(String name, int quantity) {
this.name = name;
this.quantity = quantity;
}
public String getName() { return name; }
public float getQuantity() { return quantity; }
}
Portfolio.java
import java.util.List;
public class Portfolio {
private List<Stock> stocks;
private StockService stockService;
private Float portfolioValue;
public Portfolio(List<Stock> stocks, Float portfolioValue) {
this.stocks = stocks;
this.portfolioValue = portfolioValue;
}
public void setStockService(StockService stockService) { this.stockService = stockService; }
public Float calculateMarketValue() {
Float marketValue = 0.0f;
for(Stock stock: this.stocks) {
marketValue += (stock.getQuantity()*stockService.getRealtimePrice(stock.getName()));
}
return marketValue;
}
public Boolean isInProfit() {
return (portfolioValue<calculateMarketValue()?true:false);
}
}
StockService.java
public interface StockService {
public float getRealtimePrice(String name);
}
pom.xml
<project>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.5.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-runner</artifactId>
<version>1.5.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>3.5.13</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<finalName>mockito-basic</finalName>
</configuration>
</plugin>
</plugins>
</build>
</project>
PortfolioTest.java
//@RunWith(MockitoJUnitRunner.class)
public class PortfolioTestMockAnnotations {
//@Rule public MockitoRule rule = MockitoJUnit.rule();
@Mock
StockService stockService;
@InjectMocks
Portfolio portfolio;
@BeforeAll
static void setUp() {
}
@BeforeEach
void init(){
MockitoAnnotations.initMocks(this);
System.out.println(stockService);
when(stockService.getRealtimePrice("infosys")).thenReturn(2200.0f);
when(stockService.getRealtimePrice("reliance")).thenReturn(3100.0f);
when(stockService.getRealtimePrice("indiamart")).thenReturn(4000.0f);
List<Stock> stocks = new ArrayList<>();
stocks.add(new Stock("infosys",10));
stocks.add(new Stock("reliance", 5));
portfolio = new Portfolio(stocks, 35000.0f);
portfolio.setStockService(stockService);
}
@Test
public void calculateMarketValueTest() {
Assertions.assertEquals(portfolio.calculateMarketValue(),37500);
}
@Test
public void calculateIsInProfitTest() {
Assertions.assertTrue(portfolio.isInProfit());
}
}
Using initmocks() in the PortfolioTest.java runs the test smoothly.
Please suggest the correct way for using @Rule & @RunWith in a smooth. Also provide brief difference between these 3 mechanisms of instantiating mocks.