为什么 Mockito 不模拟静态方法?

发布于 2024-10-08 11:31:20 字数 314 浏览 11 评论 0原文

我在这里阅读了一些有关静态方法的线程,我想我理解误用/过度使用静态方法可能导致的问题。但我并没有真正弄清楚为什么很难模拟静态方法。

我知道其他模拟框架(例如 PowerMock)可以做到这一点,但为什么 Mockito 不能?

我阅读了这篇文章,但是作者似乎非常反对静态这个词,也许这是我的理解很差。

一个简单的解释/链接会很棒。

I read a few threads here about static methods, and I think I understand the problems misuse/excessive use of static methods can cause. But I didn't really get to the bottom of why it is hard to mock static methods.

I know other mocking frameworks, like PowerMock, can do that but why can't Mockito?

I read this article, but the author seems to be religiously against the word static, maybe it's my poor understanding.

An easy explanation/link would be great.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

留蓝 2024-10-15 11:31:20

我认为原因可能是模拟对象库通常通过在运行时动态创建类来创建模拟(使用cglib)。这意味着它们要么在运行时实现一个接口(如果我没记错的话,这就是 EasyMock 所做的),要么从类继承来进行模拟(如果我没有记错的话,这就是 Mockito 所做的)。这两种方法都不适用于静态成员,因为您无法使用继承来覆盖它们。

模拟静态的唯一方法是在运行时修改类的字节代码,我认为这比继承更复杂一些。

这就是我的猜测,因为它的价值......

I think the reason may be that mock object libraries typically create mocks by dynamically creating classes at runtime (using cglib). This means they either implement an interface at runtime (that's what EasyMock does if I'm not mistaken), or they inherit from the class to mock (that's what Mockito does if I'm not mistaken). Both approaches do not work for static members, since you can't override them using inheritance.

The only way to mock statics is to modify a class' byte code at runtime, which I suppose is a little more involved than inheritance.

That's my guess at it, for what it's worth...

中二柚 2024-10-15 11:31:20

如果您需要模拟静态方法,则这是一个糟糕设计的强烈指标。通常,您会模拟被测类的依赖关系。如果您的被测类引用静态方法(例如 java.util.Math#sin),则意味着被测类恰好需要此实现(例如,准确性与速度)。如果您想从具体的正弦实现中抽象出来,您可能需要一个接口(您知道这会去哪里)?

If you need to mock a static method, it is a strong indicator for a bad design. Usually, you mock the dependency of your class-under-test. If your class-under-test refers to a static method - like java.util.Math#sin for example - it means the class-under-test needs exactly this implementation (of accuracy vs. speed for example). If you want to abstract from a concrete sinus implementation you probably need an Interface (you see where this is going to)?

紫竹語嫣☆ 2024-10-15 11:31:20

Mockito [3.4.0] 可以模拟静态方法!

  1. 替换 mockito-coremockito-inline:3.4.0< 的依赖关系/代码>.


  2. 具有静态方法的类:

    class Buddy {
      静态字符串名称() {
        返回“约翰”;
      }
    }
    
  3. 使用新方法Mockito.mockStatic()

    @Test
    无效lookMomICanMockStaticMethods(){
      assertThat(Buddy.name()).isEqualTo(“约翰”);
    
      尝试 (MockedStatic theMock = Mockito.mockStatic(Buddy.class)) {
        theMock.when(Buddy::name).thenReturn("Rafael");
        assertThat(Buddy.name()).isEqualTo(“拉斐尔”);
      }
    
      assertThat(Buddy.name()).isEqualTo(“约翰”);
    }
    

    Mockito 仅替换 try 块中的静态方法。

Mockito [3.4.0] can mock static methods!

  1. Replace mockito-core dependency with mockito-inline:3.4.0.

  2. Class with static method:

    class Buddy {
      static String name() {
        return "John";
      }
    }
    
  3. Use new method Mockito.mockStatic():

    @Test
    void lookMomICanMockStaticMethods() {
      assertThat(Buddy.name()).isEqualTo("John");
    
      try (MockedStatic<Buddy> theMock = Mockito.mockStatic(Buddy.class)) {
        theMock.when(Buddy::name).thenReturn("Rafael");
        assertThat(Buddy.name()).isEqualTo("Rafael");
      }
    
      assertThat(Buddy.name()).isEqualTo("John");
    }
    

    Mockito replaces the static method within the try block only.

剩一世无双 2024-10-15 11:31:20

作为 Gerold Broser 的答案的补充,这里是一个使用参数模拟静态方法的示例:

class Buddy {
  static String addHello(String name) {
    return "Hello " + name;
  }
}

...

@Test
void testMockStaticMethods() {
  assertThat(Buddy.addHello("John")).isEqualTo("Hello John");

  try (MockedStatic<Buddy> theMock = Mockito.mockStatic(Buddy.class)) {
    theMock.when(() -> Buddy.addHello("John")).thenReturn("Guten Tag John");
    assertThat(Buddy.addHello("John")).isEqualTo("Guten Tag John");
  }

  assertThat(Buddy.addHello("John")).isEqualTo("Hello John");
}

As an addition to the Gerold Broser's answer, here an example of mocking a static method with arguments:

class Buddy {
  static String addHello(String name) {
    return "Hello " + name;
  }
}

...

@Test
void testMockStaticMethods() {
  assertThat(Buddy.addHello("John")).isEqualTo("Hello John");

  try (MockedStatic<Buddy> theMock = Mockito.mockStatic(Buddy.class)) {
    theMock.when(() -> Buddy.addHello("John")).thenReturn("Guten Tag John");
    assertThat(Buddy.addHello("John")).isEqualTo("Guten Tag John");
  }

  assertThat(Buddy.addHello("John")).isEqualTo("Hello John");
}
拥有 2024-10-15 11:31:20

Mockito返回对象,但static意味着“类级别,而不是对象级别”,因此mockito会给static带来空指针异常。

Mockito returns objects but static means "class level,not object level"So mockito will give null pointer exception for static.

我ぃ本無心為│何有愛 2024-10-15 11:31:20

我认真地认为,如果您也需要模拟静态方法,那就是代码味道。

  • 访问常用功能的静态方法? ->使用单例实例并注入
  • 第三方代码? ->将其包装到您自己的接口/委托中(如果需要,也将其设为单例)

唯一一次对我来说似乎有点过分,是像 Guava 这样的库,但您无论如何都不应该需要模拟这种类型,因为它是逻辑的一部分...(像 Iterables.transform(..) 之类的东西)
这样您自己的代码就保持干净,您可以以干净的方式模拟所有依赖项,并且您拥有针对外部依赖项的反腐败层。
我在实践中见过 PowerMock,但我们需要它的所有类都设计得很糟糕。此外,PowerMock 的集成有时会导致严重问题
(例如 https ://code.google.com/p/powermock/issues/detail?id=355)

PS:私有方法也同样如此。我认为测试不应该了解私有方法的细节。如果一个类如此复杂以至于它试图模拟私有方法,那么这可能是拆分该类的标志......

I seriously do think that it is code smell if you need to mock static methods, too.

  • Static methods to access common functionality? -> Use a singleton instance and inject that
  • Third party code? -> Wrap it into your own interface/delegate (and if necessary make it a singleton, too)

The only time this seems overkill to me, is libs like Guava, but you shouldn't need to mock this kind anyway cause it's part of the logic... (stuff like Iterables.transform(..))
That way your own code stays clean, you can mock out all your dependencies in a clean way, and you have an anti corruption layer against external dependencies.
I've seen PowerMock in practice and all the classes we needed it for were poorly designed. Also the integration of PowerMock at times caused serious problems
(e.g. https://code.google.com/p/powermock/issues/detail?id=355)

PS: Same holds for private methods, too. I don't think tests should know about the details of private methods. If a class is so complex that it tempts to mock out private methods, it's probably a sign to split up that class...

晨曦÷微暖 2024-10-15 11:31:20

在某些情况下,静态方法可能很难测试,特别是当它们需要被模拟时,这就是为什么大多数模拟框架不支持它们的原因。我发现 这篇博客文章对于确定如何模拟静态方法和类非常有用。

In some cases, static methods can be difficult to test, especially if they need to be mocked, which is why most mocking frameworks don't support them. I found this blog post to be very useful in determining how to mock static methods and classes.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文