Mockito:如何验证在非静态方法中调用了静态方法?

huangapple go评论69阅读模式
英文:

Mockito: how verify static method called in non-static method?

问题

我有一个`Animal.class`:

```java
class Animal {
    int counter;
    public void move() {
        counter += getRandomNumber(1, 10);
    }

    public static int getRandomNumber(int min, int max) {
        return new Random().nextInt(min, max);
    }
}

我使用Mockito 5.2.0

尝试使用mockedStatic接口验证getRandomNumber方法:

@Test
void tryVerifyStaticMethod() {
    try (MockedStatic<Animal> mockedStatic = mockStatic(Animal.class)) {
        mockedStatic.verify(() -> Animal.getRandomNumber(1, 10), times(1));
    }
}

但我不知道如何在测试中调用非静态的move()方法以调用getRandomNumber方法。


<details>
<summary>英文:</summary>

I have `Animal.class`:

class Animal {
int counter;
public void move() {
counter += getRandomNumber(1, 10);
}

public static int getRandomNumber(int min, int max) {
    return new Random().nextInt(min, max);
}

}


I use `Mockito 5.2.0`.

Tried verify `getRandomNumber` method with `mockedStatic` interface:

    @Test
    void tryVerifyStaticMethod() {
        try (MockedStatic&lt;Animal&gt; mockedStatic = mockStatic(Animal.class)) {
            mockedStatic.verify(() -&gt; Animal.getRandomNumber(1, 10), times(1));
        }
    }

But I don&#39;t know how call non-static `move()` method in the test for invoking `getRandomNumber` method.

</details>


# 答案1
**得分**: 2

以下是您要翻译的内容:

如果您想调用一个正在调用您的静态模拟的方法,您可以在try块中简单地执行它。只要您的静态模拟存在,它将用于这些调用。

这意味着,您的测试可以如下所示:

```java
@Test
void tryVerifyStaticMethod() {

    try (MockedStatic&lt;Animal&gt; mockedStatic = mockStatic(Animal.class)) {

        // 如果需要,为您的静态模拟设置一些行为
        mockedStatic.when(() -&gt; Animal.getRandomNumber(1, 10)).thenReturn(42);

        // 创建一个新的Animal实例
        Animal animal = new Animal();

        // 调用要测试的方法
        animal.move();

        // 断言计数器已更改
        assertEquals(42, animal.counter);

        // 验证随机数方法的调用
        mockedStatic.verify(() -&gt; Animal.getRandomNumber(1, 10), times(1));
    }

}

只要您在try块内部调用move(),所有对您的Animal类的静态调用都将使用mockedStatic对象及其所有行为。在这个示例中,我设置了每当调用具有min = 1和max = 10的getRandomNumber方法时返回42的行为。

英文:

If you want to call a method that is calling your static mocks, you can do it simply in the try-block. As long as your static mock is present, it will be used for the calls.

This means, your test could look like the following:

@Test
void tryVerifyStaticMethod() {

    try (MockedStatic&lt;Animal&gt; mockedStatic = mockStatic(Animal.class)) {

        // Giving your static mock some behaviour if you want
        mockedStatic.when(() -&gt; Animal.getRandomNumber(1, 10)).thenReturn(42);

        // creating a new instance of animal
        Animal animal = new Animal();

        // calling the method under test
        animal.move();

        // asserting that the counter has changed
        assertEquals(42, animal.counter);

        // verifying the call of the random number method
        mockedStatic.verify(() -&gt; Animal.getRandomNumber(1, 10), times(1));
    }

}

As long as you are calling move() inside the try, all the static calls to your Animal class will use the mockedStatic object and all of its behaviours. In this example case, I gave the behaviour to return 42 whenever getRandomNumber with min = 1 and max = 10 is called.

答案2

得分: 1

以下是您要翻译的内容:

首先,不要测试类的内部细节,而是测试其行为。在您的情况下,我会像这样重写动物类:

class Animal {
    int counter;
    Random random;
    public Animal(Random random) {
        this.random = random;
    }

    public void move() {
        counter += getRandomNumber(1, 10);
    }

    // 必须有一个方法显示调用move()的效果
    public int getCounter() {
         return counter;
    }

    private int getRandomNumber(int min, int max) {
        return random.nextInt(min, max);
    }
}

然后您的测试如下所示:

@Test
public void testMove() {
    Random random = mock(Random.class);
    when(random.nextInt(1, 10)).thenReturn(5);
    Animal animal = new Animal(random);
    animal.move();
    assertEquals(5, animal.getCounter());
}

避免在您希望进行测试的类中调用 new。如果您愿意,可以将 getRandomNumber 设置为 static,并将 Random 实例作为参数传递给它,但我没有看到这样做的好理由。

英文:

First, don't test the internal details of your class, test its behaviour. In your case I would rewrite animal like this:

class Animal {
    int counter;
    int Random random;
    public Animal(Random random) {
     this.random = random;
    }

    public void move() {
        counter += getRandomNumber(1, 10);
    }

    // there must be some method which shows the effect of calling move()
    public int getCounter() {
         return counter;
    }

    private int getRandomNumber(int min, int max) {
        return random.nextInt(min, max);
    }
}

Then your test becomes:

@Test
public void testMove() {
    Random random = mock(Random.class);
    when(random.nextInt(1, 10)).thenReturn(5);
    Animal animal = new Animal(random);
    animal.move();
    assertEquals(5, animal.getCounter());
}

Avoid calling new in classes which you wish to test.
You can keep getRandomeNumber as static, if you wish, and pass it the Random instance as a parameter, but I don't see any good reason to do that.

huangapple
  • 本文由 发表于 2023年5月21日 08:30:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/76297839.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定