如何使用最终方法来模拟类?

发布于 2024-07-08 03:45:47 字数 1511 浏览 11 评论 0原文

假设我有 A 类,

class A {
  final String foo() {
    // .. computing result, contacting database, whatever ..
    return "some computed value";
  }
  // ... and a bazillion other methods, some of them final.
}

现在我有 B 类,

class B {
  String methodIWantToTest(A a) {
      String output = a.foo();
      // ... whatever this method does, e.g.:
      output += "_suffix";
      return output;
  }
}

我将如何对该方法进行单元测试? foo() 是 Final 的原因是我们不希望扩展 A 的类改变其功能。 但同时为了真正对该方法进行单元测试,我不希望它伸出并运行实际的 A.foo() 方法。

有没有办法,比如说,删除final关键字并沿着@finalUnlessTest添加注释? 你会推荐什么? 将 A 重构为接口将非常非常困难,因为它是我们的中心类之一,并且不幸的是相当极其耦合。

编辑 #1 抱歉,忘了提及,我们正在谈论 Java。 到目前为止我们还没有使用模拟框架。

回答 好的,所以:哇。 JMockit 令人难以置信,在我眼中是测试遗留代码的杀手级应用程序。 难以置信的有用,尤其是对我来说。 非常感谢! 对于我的伪示例,您基本上会执行以下操作:

class AMock {
   final String foo() {
     return "myTestValue";
   }
}
class Test extends TestCase {
   A mockedA;
   B b;
   protected void setUp() {
      Mockit.redefineMethods( A.class, AMock.class );  // this "pipes" all mocked methods from A to AMock
      mockedA = new A();    // NOT new AMock()!!!
      b = new B();
   }
   public void testB() {
      assertEquals("myTestValue",mockedA.foo());
      assertEquals("myTestValue_suffix",b.methodIWantToTest(mockedA));
   }
}

这该死的很酷还是什么?

Say I have class A with

class A {
  final String foo() {
    // .. computing result, contacting database, whatever ..
    return "some computed value";
  }
  // ... and a bazillion other methods, some of them final.
}

Now I have class B with

class B {
  String methodIWantToTest(A a) {
      String output = a.foo();
      // ... whatever this method does, e.g.:
      output += "_suffix";
      return output;
  }
}

How would I go about unit testing this method? The reason foo() is final is because we don't want our classes which extend A to change its functionality. But at the same time to truly unit test the method, I don't want it to reach out and run the actual A.foo() method.

Is there a way to, say, remove the final keyword and add an annotation along the lines of @finalUnlessTest? What would you recommend? Refactoring A to an interface would be very, very difficult, seeing as how it's one of our central classes and is unfortunately pretty extremely coupled.

Edit #1 Sorry, forgot to mention, we're talking Java. We are not using a mocking framework as of yet.

Answer OK, so: wow. JMockit is just incredible and is in my eyes the killer app for testing legacy code. Unbelievably useful especially in my case. Thanks so much! You basically would do something like the following for my psuedo-example:

class AMock {
   final String foo() {
     return "myTestValue";
   }
}
class Test extends TestCase {
   A mockedA;
   B b;
   protected void setUp() {
      Mockit.redefineMethods( A.class, AMock.class );  // this "pipes" all mocked methods from A to AMock
      mockedA = new A();    // NOT new AMock()!!!
      b = new B();
   }
   public void testB() {
      assertEquals("myTestValue",mockedA.foo());
      assertEquals("myTestValue_suffix",b.methodIWantToTest(mockedA));
   }
}

Is this frickin' cool or what?

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

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

发布评论

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

评论(3

十雾 2024-07-15 03:45:47

您可以尝试 JMockit 模拟库。

You can try the JMockit mocking library.

ι不睡觉的鱼゛ 2024-07-15 03:45:47

我会删除“final”并添加注释“不要覆盖此方法!!”。 如果你不能相信同事不会遵循简单的指示,那么无论如何都是没有希望的。

I'd remove the "final" and just put in a comment "Don't override this method!!". If you can't trust coworkers not to follow simple instructions, it's hopeless anyway.

岁月蹉跎了容颜 2024-07-15 03:45:47

下面的代码也将允许您执行此操作。 我并不是说这是一个好的实践,但这是匿名类的一个有趣的使用(滥用?)。

public class Jobber {

    public final String foo() {
        return fooFactory() ;
    }

    String fooFactory() {
        return "jobber" ;
    }


    public static void main(String[] args) {

        Jobber jobber = new Jobber() { String fooFactory() { return "prefix " + super.fooFactory() ;} } ;

        System.out.println(jobber.foo() );
    }
}

The following code will also allow you to do it. I am not saying that this is good practice, but it is an interesting use (abuse?) of anonymous classes.

public class Jobber {

    public final String foo() {
        return fooFactory() ;
    }

    String fooFactory() {
        return "jobber" ;
    }


    public static void main(String[] args) {

        Jobber jobber = new Jobber() { String fooFactory() { return "prefix " + super.fooFactory() ;} } ;

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