微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

无法使用@Rule和@RunWith批注,但已弃用的initmocks可以工作

如何解决无法使用@Rule和@RunWith批注,但已弃用的initmocks可以工作

我正在研究一个简单的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()可以平稳地运行测试。

enter image description here


使用@Rule ,引发NPE

enter image description here


使用@RunWith ,引发NPE

enter image description here


请提出正确使用@Rule和@RunWith的正确方法。还提供了这三种实例化模拟机制之间的简要区别。

解决方法

您的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

,

在 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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。