当Mock对象遭遇继承


java 代码
  1. class A{
  2. public String a(){
  3. return a;
  4. }
  5. }
  6. public class B extends A{
  7. public String b(){
  8. return b;
  9. }
  10. }

上面所示的是一个很常见的继承结构,但是就是这样的结构导致了在Mock对象时会产生某些令人困惑的问题。

假如在BConsumer这个类中用到了B,那么就需要把B的实例(这里先不讨论应该抽象出接口与否的问题)注入到BConsumer中去。如果我们要模拟的是b()这个方法,那自然一切都没问题。我这里用的是JMock来mock具体类:

java 代码
  1. Mockery context = new JUnit4Mockery() {
  2. {
  3. setImposteriser(ClassImposteriser.INSTANCE);
  4. }
  5. };
  6. ……
  7. @Test
  8. public void xxx(){
  9. BConsumer consumer = new BConsumer();
  10. B b = context.mock(B.class);
  11. context.checking(new Expectations(){{
  12. allowing(b).b();
  13. }});
  14. consumer.setB(b);
  15. ……
  16. }


可是如果我们需要模拟a()这个方法时,问题就出现了。

java 代码
  1. @Test
  2. public void xxxxx(){
  3. BConsumer consumer = new BConsumer();
  4. B b = context.mock(B.class);
  5. context.checking(new Expetations(){{
  6. allowing(b).a();
  7. }});
  8. consumer.setB(b);
  9. ……
  10. }

我们可以按照上面这种方式来写Mock么?当然不行!我们Mock的是B,但是实际调用的则是A中的方法a()!

那么可能就有人想到或许可以这样做:

java 代码
  1. @Test
  2. public void xxxxx(){
  3. BConsumer consumer = new BConsumer();
  4. A a = context.mock(A.class);
  5. context.checking(new Expetations(){{
  6. allowing(a).a();
  7. }});
  8. consumer.setB((B)a);
  9. ……
  10. }

但实际上,到了 consumer.setB((B)a);这一步的时候,我们得到的a实际上是通过cglib生成的对象,要转型成B就会出现ClassCastException。

那我们到底该怎么做才好呢?难道为了Mock测试的需要,就在B中把A中的a()重写一遍?如果要抽象出接口来,又该怎样抽象才合情合理?

恳请赐教。

猜你喜欢

转载自dearwolf.iteye.com/blog/126894