2

我正在 JMockit 中寻找一种在类中注入私有字段的方法,同时保持触发真实方法的能力。我使用@Injectable并由@TestedJMockit 提供。但不知何故,注入的实例无法调用真正的方法。

示例测试:

public class TestClass {
    public static class DoSomething {
        private Call callee;

        public void execute() {
            callee.call();
        }
    }

    public static class Call {
        public void call() {
            System.out.println("real");
        }
    }

    @Tested DoSomething doSomething;
    @Injectable Call call;

    // nothing happens
    @Test
    public void testRealCall() {
        doSomething.execute();
    }

    // invocation doesn't help either
    @Test
    public void testRealCallSecondTry() {
        new MockUp<Call>() {
            @Mock
            @SuppressWarnings("unused")
            public void call(Invocation inv) {
                inv.proceed();
            }
        };
        doSomething.execute();
    }

    // this works, but requires redundant methods
    @Test
    public void testRealCallThirdTry() {
        new MockUp<Call>() {
            @Mock
            @SuppressWarnings("unused")
            public void call() {
                System.out.println("real");
            }
        };
        doSomething.execute();
    }

    @Test
    public void testFakeCall() {
        new MockUp<Call>() {
            @Mock
            @SuppressWarnings("unused")
            public void call() {
                System.out.println("fake");
            }
        };
        doSomething.execute();
    }
}

这里DoSomething包装了Call实例,它提供了一种打印消息的方法。四个测试用例的理想输出是:

real
real
real
fake

然而实际情况是只有 3 和 4 工作,打印:

real
fake

这显示了是否使用@Injectable. 如果不将旧方法体复制并粘贴到模拟版本,则无法直接调用原始方法。这似乎真的很尴尬。有解决方法吗?

4

2 回答 2

2

我的理解是,如果您使用@Injectable,您只会得到一个空的模拟,然后您就不能再调用原始方法。

我将使用的解决方法是像这样“手动”进行注入:

public class TestClass {
  public static class DoSomething {
    private Call callee;

    public void execute() {
      callee.call();
    }
  }

  public static class Call {
    public void call() {
      System.out.println("real");
    }
  }

  @Tested DoSomething doSomething;
  //@Injectable Call call;

  // nothing happens
  @Test
  public void testRealCall() {
    Deencapsulation.setField(doSomething, "callee", new Call());
    doSomething.execute();
  }

  // invocation doesn't help either
  @Test
  public void testRealCallSecondTry() {
    new MockUp<Call>() {
      @Mock
      @SuppressWarnings("unused")
      public void call(Invocation inv) {
        inv.proceed();
      }
    };
    Deencapsulation.setField(doSomething, "callee", new Call());
    doSomething.execute();
  }

  // this works, but requires redundant methods
  @Test
  public void testRealCallThirdTry() {
    new MockUp<Call>() {
      @Mock
      @SuppressWarnings("unused")
      public void call() {
        System.out.println("real");
      }
    };
    Deencapsulation.setField(doSomething, "callee", new Call());
    doSomething.execute();
  }

  @Test
  public void testFakeCall() {
    new MockUp<Call>() {
      @Mock
      @SuppressWarnings("unused")
      public void call() {
        System.out.println("fake");
      }
    };
    Deencapsulation.setField(doSomething, "callee", new Call());
    doSomething.execute();
  }
}
于 2013-11-12T08:36:13.763 回答
0

当我遇到同样的问题时,我遇到了这个问题。但是,现有答案不适用于较新版本的 JMockit。

如果测试类中的某个字段用 注释@Inject,则测试类中需要对应@Injectable。通常。这意味着删除@Injectable并用其他答案中的建议来模拟类MockUp是行不通的。JMockit 会抱怨“Missing @Injectable for field ...”。

相反,需要做的是将@Injected注解更改为@Tested注解,即更改此

@Injectable Call call;

@Tested Call call;

call成为一个真实的实例,JMockit 不会抱怨缺少@Injectable. 如果需要 mock中的某些方法call,可以MockUp照常进行。

new MockUp<Call>() {
  @Mock
  public void someMethodToMock() {
  }
};
于 2021-06-29T14:32:27.543 回答