@Mock是做什么的?我可以在@BeforeClass中使用它吗?

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

What does @Mock do? Can I use it with @BeforeClass?

问题

这在 beforeClass() 中引发了空指针异常,因为 o 为 null:

@RunWith(MockitoJUnitRunner.class)
public class FooTest {
    @Mock
    private static Object o;

    @BeforeClass
    public static void beforeClass() {
        when(o.toString()).thenReturn("foo");
    }

    @Test
    public void test() {
        o.toString();
    }
}

然而,如果我将它改成非静态的 @Before 方法,就可以通过测试。如果我使用 = mock(Object.class) 而不是 @Mock,也可以通过测试。

这看起来很奇怪。我是否漏掉了关于 @Mock 的某些内容?如果它的唯一目的是为了让你不必编写 mock(MyClass.class)(同时强制你添加 @RunWith(MockitoJUnitRunner.class)),但它不允许你使用 @BeforeClass,似乎是一个不必要的元素,应该被弃用。还是我漏掉了允许同时使用这两个元素的某些内容?

英文:

This throws NPE in beforeClass() because o is null:

@RunWith(MockitoJUnitRunner.class)
public class FooTest {
    @Mock
    private static Object o;

    @BeforeClass
    public static void beforeClass() {
        when(o.toString()).thenReturn("foo");
    }

    @Test
    public void test() {
        o.toString();
    }
}

However, if I make it a non-static @Before method, it passes. If instead of using @Mock I write = mock(Object.class), it passes.

This seems strange. Is there anything I'm missing about @Mock? If its only purpose is to save you from writing mock(MyClass.class) (while forcing you to add @RunWith(MockitoJUnitRunner.class)), but it prevents you from using @BeforeClass, it seems like an unnecessary element that should be deprecated. Or is there something I'm missing that would allow me to use both these elements?

答案1

得分: 2

@Mock和Mockito.mock(MyClass.class)都具有相同的功能。主要区别在于大多数人认为@Mock更清晰。

在你的测试中需要提到不同的要点:

  • @BeforeEach需要使用静态字段和静态方法,因为其中执行的方法是在初始化阶段执行的,即在创建类的实例之前执行。
  • @Mock在@BeforeClass之后执行,这就是为令这些注解不能一起使用(在执行BeforeClass时尚未创建模拟对象)。
  • 使用Mockito.mock(MyClass.class)强制在带有@BeforeClass注解的方法执行期间创建模拟对象,这就是为什么它能正常工作的原因。
英文:

@Mock and Mockito.mock(MyClass.class) both have the same function. The main difference is that @Mock is considered by most as cleaner.

There are different points to mention in your tests:

  • @BeforeEach require to use static fields and static methods as the methods executed in it are done during the initialisation phase, meaning before creating instances of classes.
  • @Mock is executed after @BeforeClass, that why those annotations don't work together (the mock is not yet created when executing BeforeClass).
  • Using Mockito.mock(MyClass.class) forces to create the mock during the execution of the method annotated with @BeforeClass, this is why it works.

答案2

得分: 1

Sure, here's the translated text:

但是,如果我将其变成非静态的@Before方法,它就会通过。如果我不使用@Mock,而是写= mock(Object.class),它也会通过。
这看起来很奇怪。我是否遗漏了@Mock的某些内容?

@Mock只是一个标记字段为模拟对象的注解。必须有“某物”来填充这些字段以创建模拟对象。根据文档,你可以使用MockitoJUnitRunnerinitMocks来实现这一点。

如果你使用了运行器,就像你所示范的那样,那么你的模拟对象只会在运行器执行之后准备好,而在Mockito运行器中,运行器会在每个测试之前执行,但是在类初始化之后执行。

如果它的唯一目的是为了省去编写mock(MyClass.class)(同时强制你添加@RunWith(MockitoJUnitRunner.class)),但它阻止你使用@BeforeClass,那么它似乎是一个不必要的元素,应该被废弃。或者是我遗漏了什么,可以让我同时使用这两个元素吗?

你试图在一个明显设计用于实例字段的API上使用一个静态字段。所以它并不是“不必要”的,只是不适用于你的用例。

对于你的情况,最简单的做法是移除RunsWith注解,并且可以内联模拟对象,就像你已经指示的那样:o = mock(MyObject.class)

英文:

> However, if I make it a non-static @Before method, it passes. If instead of using @Mock I write = mock(Object.class), it passes.
This seems strange. Is there anything I'm missing about @Mock?

@Mock is just an annotation that marks fields as being mock objects. Something has to fill in those fields with mocks. Per the documentation, you can do that with MockitoJUnitRunner or with initMocks.

If you do it with the runner, as you have illustrated, then your mocks will only be ready after the runner executes and in Mockito runners execute before each test but after the class has been initialized.

> If its only purpose is to save you from writing mock(MyClass.class) (while forcing you to add @RunWith(MockitoJUnitRunner.class)), but it prevents you from using @BeforeClass, it seems like an unnecessary element that should be deprecated. Or is there something I'm missing that would allow me to use both these elements?

You are trying to use an API that seems to be designed for instance fields on a static field. So it's not "unnecessary", it's just not applicable to your use case.

The easiest thing to do for your case would be to remove the RunsWith annotation and <strike>call initMocks as the first call in your beforeClass method</strike> just mock the object inline, as you already indicated: o = mock(MyObject.class).

huangapple
  • 本文由 发表于 2023年5月10日 20:14:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/76218290.html
匿名

发表评论

匿名网友

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

确定