【问题标题】:JUnit mocking with Mockito, EasyMock, etc使用 Mockito、EasyMock 等进行 JUnit 模拟
【发布时间】:2010-10-14 12:50:16
【问题描述】:

我正在尝试在我正在测试的类中模拟一个对象的方法。

例如

class ClassToTest {
   public doSomething () {
       SomeObject a = new SomeObject ();
       a.doSomethingElse ();
   }
}

有没有办法模拟变量“a”的方法?我希望 doSomethingElse 在测试期间什么都不做。我目前正在使用 Mockito,但我对任何模拟框架都持开放态度。

谢谢

【问题讨论】:

    标签: java junit mocking easymock mockito


    【解决方案1】:

    是的,有办法,如下JMockit测试所示:

    public void testDoSomething(final SomeObject mock)
    {
        new ClassToTest().doSomething();
    
        new Verifications() {{ mock.doSomethingElse(); }};
    }
    

    无需重构被测代码以使用包装器、DI 等;只需模拟您需要模拟的任何内容。

    【讨论】:

      【解决方案2】:

      当引用“a”被声明为局部变量时,不可能模拟引用“a”,就像你的情况一样。您可以考虑将依赖项注入到 SomeObject,例如作为 doSomething 方法的参数。这样,您可以在测试中注入 SomeObject 的模拟。

      dependency injection is increased testability 的好处之一。

      【讨论】:

        【解决方案3】:

        当然,通过一些重构是可能的:

        class SomeObject {
            public void doSomethingElse()
            {
        
            }
        }
        
        class ClassToTest
        {
            private final SomeObject someObject;
        
            public void doSomething()
            {
                someObject.doSomethingElse();
            }
        
            public ClassToTest(SomeObject someObject)
            {
                this.someObject = someObject;
            }
        }
        
        class Test {
            @Test
            public void testDoSomething()
            {
                SomeObject someObject = Mockito.mock(SomeObject.class);
                new ClassToTest(someObject).doSomething();
                Mockito.verify(someObject, Mockito.atLeastOnce()).doSomethingElse();
            }
        }
        

        【讨论】:

        • 是的,这也是我的想法。我只是不确定是否可以模拟局部变量(还)
        【解决方案4】:

        我相信您可以将EasyMock Class Extensions 用于 EasyMock 2.5 或更早版本,并且显然它包含在 3.0 中。请参阅this part of the previous page 以获取有关您尝试做什么的信息。也就是说,我没有亲自尝试过这样做,所以我不知道它的效果如何。

        【讨论】:

        • 使用 EasyMock 类扩展,您可以模拟类,您只能模拟没有类扩展的接口。但是,您不能模拟声明为局部变量的引用。
        【解决方案5】:

        如果您希望在每次调用中都有一个新实例,我建议您通过以下方式进行重构:

        class ClassToTest {
           public doSomething () {
              SomeObject a = getInstance();
              a.doSomethingElse ();
           }
           protected SomeObject getInstance() {
              return new SomeObject();
           }
        }
        

        然后您可以创建一个扩展 ClassToTest 的测试类,覆盖 getInstance() 方法,并提供一个模拟对象。

        这当然只有在您可以公开 getInstance() 方法时才可行,所以如果该类是公共 API 的一部分,我不建议这样做。如果是这种情况,请考虑使用依赖注入提供工厂类。

        【讨论】:

        • 如果你走这条路,我想我会创建一个提供者(工厂)并注入它。一个像样的 DI 框架(比如 Guice)将为您创建工厂。
        【解决方案6】:
        class ClassToTest {
            private SomethingElseInterface somethingElseDoer ;
        
            public ClassToTest(SomethingElseInterface somethingElseDoer) {
                this.somethingElseDoer = somethingElseDoer;
            }
        
            public doSomething () {
                somethingElseDoer.doSomethingElse();
            }
        }
        

        以及你在哪里使用它:

        SomethingElseInterface somethingElseDoer = ...; // in a test, this is where you mock it
        ClassToTest foo = new ClassToTest(somethingElseDoer); // inject through constructor
        foo.doSomething();
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-07-31
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多