Java Junit Mockito mock未按预期工作

Java Junit Mockito mock未按预期工作,java,spring-boot,junit,mockito,powermock,Java,Spring Boot,Junit,Mockito,Powermock,我有一个TestClass,我正在为TestClass的calculate()方法编写单元测试用例。请参考下面的代码 public class TestClass { public int calculate() { System.out.println("calculating area"); String shape = getShape(1); int radius = 10; int result = findA

我有一个
TestClass
,我正在为
TestClass
calculate()
方法编写单元测试用例。请参考下面的代码

public class TestClass {

    public int calculate() {

        System.out.println("calculating area");
        String shape = getShape(1);
        int radius = 10;
        int result = findArea(shape, radius);
        return result;
    }

    public String getShape(int index) {
        if(index == 1) {
            return "circle";
        }
        else {
            return "square";
        }
    }

    public int findArea(String shape, int radius) {
        if(shape == "circle") {
            return 3 * radius * radius;
        }
        else {
            return radius * radius;
        }
    }
}
在模拟getShape()函数时,我希望在传递值1时模拟返回“square”。请参考下面的单元测试

import static org.junit.jupiter.api.Assertions.assertEquals;

import org.junit.Before;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;

public class TestClassTest {
    //TestClass testClass;

    @Before
    public void init() {
        TestClass testClass = new TestClass();
        System.out.println("Inside before");
    }

    @Test
    public void calculateTest() {
        int expected = 100;
        TestClass testClass = new TestClass();
        TestClass testClassMock = Mockito.mock(TestClass.class);
        Mockito.when(testClassMock.getShape(1)).thenReturn("square");
        int actual = testClass.calculate();
        assertEquals(expected, actual);
    }

}

测试失败,出现错误,预期为100,但实际为300。因此很明显,
getShape(1)
返回值圆,而不是我使用
Mockito.when()提供的值。请告诉我我犯了什么错误。

你在模拟一个对象,但是你从来没有使用过这个模拟。看起来您的意图是监视(即,部分模拟)受测对象,使
getShape
被模拟掉,但
calculate
的实际实现被称为:

@测试
public void calculateTest(){
int预期为100;
TestClass TestClass=Mockito.spy(新的TestClass());
Mockito.doReturn(“square”).when(testClass).getShape(1);
int actual=testClass.calculate();
资产质量(预期、实际);
}

问题是,当您创建了两个单独的类实例
TestClass
,然后用一个类实例TestClass
TestClass
调用方法
calculate
,并且在单独的实例
testClassMock
中模拟并分配返回值时,因此,在运行测试用例时,模拟的值不起任何作用

    TestClass testClass = new TestClass();
    TestClass testClassMock = Mockito.mock(TestClass.class);
简单的解决方案是,您应该有单个实例来调用测试方法和模拟方法,有关更多详细信息,请访问以下问题:

对于您的解决方案,以下是代码:

TestClass testClass = Mockito.spy(new TestClass());
Mockito.doReturn("square").when(testClass).getShape(ArgumentMatchers.anyInt());
int actual = testClass.calculate(); 

另一个答案建议你可以使用间谍。我宁愿使用
@Spy
注释对其进行初始化,并完全摆脱您的
@Before
方法,如下所示:

@Spy
private TestClass testClass;

@Test
public void calculateTest() {
    int expected = 100;
    Mockito.when(testClass.getShape(1)).thenReturn("square");
    int actual = testClass.calculate();
    assertEquals(expected, actual);
}

// This just to show that if you do not spy any methods it works as "normal" TestClass

@Test
public void calculateTestNotSpied() {
    int expected = 300;
    int actual = testClass.calculate();
    assertEquals(expected, actual);
}

此外,我不确定这是否是一个大问题,但您似乎混合了Junit4和Junit5(Jupiter)注释和断言。在测试中只使用其中一个(4 | 5)可能是一个好主意。

仅在将对象用作spring实例时进行模拟是模拟的主要要求,这一点已被经常讨论

理解mockito.doReturn()和mockito.init()的顺序也很重要。确保首先调用mockito.init

您可以通过注释来实现这一点,以确保init()始终是第一位的。
-AB

它的Mockito.doReturn(“正方形”).when(testClass).getShape(1);是吗?@das yes-编辑我从你的问题复制到答案的代码时,没有注意到这一点。谢谢你的关注!已编辑并修复。@das,我们可以使用Mockito.doReturn(“square”).when(testClass.getShape(1)形式;用嘲弄或间谍。我认为它在编码UTs方面给了我们更多的灵活性。