How to go about mocking a class with final methods?

左心房为你撑大大i 提交于 2019-12-09 12:01:25

问题


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?


回答1:


You can try the JMockit mocking library.




回答2:


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.




回答3:


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() );
    }
}


来源:https://stackoverflow.com/questions/190597/how-to-go-about-mocking-a-class-with-final-methods

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!