【问题标题】:Not able to use @Rule & @RunWith annotation, but the deprecated initmocks() works无法使用 @Rule 和 @RunWith 注释,但已弃用的 initmocks() 有效
【发布时间】:2021-02-04 17:19:29
【问题描述】:

我正在学习一个简单的 Java 程序的基本测试驱动开发学习,该程序为股票提供投资组合价值。

我有 2 个课程,Portfolio.javaStock.java,它们描述了投资组合和股票模型。以抽象方式使用接口StockService.java获取实时股票价格。

PortfolioTest.java 是我尝试通过使用 Mockito 模拟此 StockService 来为投资组合功能编写单元测试的类。

我可以使用已弃用的 MockitoAnnotations.initMocks(this); 并运行我的测试,但如果尝试使用 @Rule@RunWith 注释,则会出现空指针异常。

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());
    }
}

在 PortfolioTest.java 中使用 initmocks() 可以顺利运行测试。


使用@Rule,抛出 NPE


使用@RunWith,抛出 NPE


请提出正确使用@Rule & @RunWith 的方法。还提供这 3 种实例化 mock 机制之间的简要区别。

【问题讨论】:

    标签: java unit-testing mockito junit4 junit5


    【解决方案1】:

    在 Junit5 中,@RunsWith() 被替换为 @ExtendWith({MockitoExtension.class}),其中 MockitoExntension 来自于

       <!-- https://mvnrepository.com/artifact/org.mockito/mockito-junit-jupiter -->
         <dependency>
             <groupId>org.mockito</groupId>
             <artifactId>mockito-junit-jupiter</artifactId>
             <version>3.11.2</version>
             <scope>test</scope>
         </dependency>
    

    3.11.2 是我发布解决方案时的当前版本。欲了解更多信息,您可以访问:Mockito and Junit5

    【讨论】:

      【解决方案2】:

      您的 POM 表明您可能会以某种方式混合使用 JUnit5 和 JUnit4。将方法声明为测试有两个注解:

      @org.junit.Test // for JUnit4
      @org.junit.jupiter.api.Test // for JUnit5
      

      如果您为 JUnit4 进行注释并以 JUnit4 测试的方式运行测试,那么一切都应该没问题。

      但是,如果您使用 JUnit5 进行注释并作为 JUnit5 测试运行,情况会有所不同。 JUnit5 不使用@Rule@RunWith,但有自己的方式来初始化模拟。 Article 这或许可以解释为什么有些东西有效而有些东西无效。

      简而言之,作为 JUnit5 运行,你的类应该有注释:

      @ExtendWith(MockitoExtension.class)
      

      因为@RuleRunWith 不再起作用了。这个注解需要依赖:

      <dependency>
          <groupId>org.mockito</groupId>
          <artifactId>mockito-junit-jupiter</artifactId>
          <version>2.23.0</version>
          <scope>test</scope>
      </dependency>
      

      我只运行 JUnit5 并且有这些依赖项

          <dependency>
              <groupId>org.junit.jupiter</groupId>
              <artifactId>junit-jupiter</artifactId>
              <version>5.5.2</version>
          </dependency>
          <dependency>
              <groupId>org.mockito</groupId>
              <artifactId>mockito-junit-jupiter</artifactId>
              <version>2.23.0</version>
              <scope>test</scope>
          </dependency>
      

      Related question

      【讨论】:

        猜你喜欢
        • 2013-03-07
        • 2015-11-11
        • 1970-01-01
        • 2012-03-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多