英文:
How to use EasyMockSupport through delegation with EasyMockRule or EasyMockRunner?
问题
以下是您要翻译的内容:
是否有可能在使用EasyMockSupport时,同时利用EasyMockRule(或EasyMockRunner)进行委托(而不是继承)?
换句话说:如何使EasyMockSupport意识到由EasyMockRule创建的模拟?
这里是一个演示我所面临问题的最小工作示例(MWE):
// 被测试的类
public class MyClass {
private Collaborator collaborator;
public MyClass() {
collaborator = new Collaborator();
}
// 待测试的方法
public int myMethod() {
return collaborator.mockedMethod() + 1;
}
}
// 要进行模拟的类
public class Collaborator {
public int mockedMethod() {
return 1;
}
}
// 测试用例
public class MyClassTest {
private EasyMockSupport easyMockSupport = new EasyMockSupport();
@Rule public EasyMockRule easyMockRule = new EasyMockRule(this);
@TestSubject private MyClass testSubject = new MyClass();
@Mock private Collaborator collaboratorMock;
@Test public void testMyMethod() {
EasyMock.expect(collaboratorMock.mockedMethod()).andReturn(2);
easyMockSupport.replayAll();
int result = testSubject.myMethod();
Assert.assertEquals("成功模拟时应返回2 + 1", 3, result);
// 抛出 java.lang.AssertionError: 期望值:<3>,但实际值:<1>
}
}
这个测试失败了,而如果MyClassTest扩展了EasyMockSupport,则测试会通过。(但是我不能为我所做的事情使用继承,因此我提出了问题。)
我对这种行为的理解是,在我的示例中,EasyMockSupport不知道Collaborator模拟,因此调用replayAll()没有效果,当在testSubject.myMethod()中调用模拟时,模拟仍然处于录制状态(因此mockedMethod()返回0)。
实际上,injectMocks()文档说明如下:
> 如果参数扩展了EasyMockSupport,则将使用它创建模拟,以便在之后可以工作replayAll/verifyAll
但是当使用委托时,参数(即测试类)不扩展EasyMockSupport。我是否漏掉了什么,或者是不可能的?
附注:我正在使用EasyMock 3.6。理想情况下,我希望找到一个保持该版本的解决方案,但如果在较新版本中有相关功能/错误修复,请随意指示。
提前感谢您的帮助!
英文:
Is it possible to leverage both EasyMockSupport
and EasyMockRule
(or EasyMockRunner
) when using EasyMockSupport
through delegation (instead of inheritance)?
In other words: how to make EasyMockSupport
aware of mocks created by EasyMockRule
?
Here is a MWE demonstrating the issue I'm facing:
// Class under test
public class MyClass {
private Collaborator collaborator;
public MyClass() {
collaborator = new Collaborator();
}
// Method under test
public int myMethod() {
return collaborator.mockedMethod() + 1;
}
}
// Class to be mocked
public class Collaborator {
public int mockedMethod() {
return 1;
}
}
// Test case
public class MyClassTest {
private EasyMockSupport easyMockSupport = new EasyMockSupport();
@Rule public EasyMockRule easyMockRule = new EasyMockRule(this);
@TestSubject private MyClass testSubject = new MyClass();
@Mock private Collaborator collaboratorMock;
@Test public void testMyMethod() {
EasyMock.expect(collaboratorMock.mockedMethod()).andReturn(2);
easyMockSupport.replayAll();
int result = testSubject.myMethod();
Assert.assertEquals("Should return 2+1 when successfully mocked", 3, result);
// throws java.lang.AssertionError: expected: <3> but was: <1>
}
}
The test fails, whereas it passes if MyClassTest
extends EasyMockSupport
. (But I can't use inheritance for what I'm doing, hence my question.)
My comprehension of this behavior is that, in my example, EasyMockSupport
isn't aware of the Collaborator
mock, so calling replayAll()
has no effect and the mock is still in record state when called in testSubject.myMethod()
(thus mockedMethod()
returning 0).
Indeed, injectMocks()
documentation says:
> If the parameter extends EasyMockSupport, the mocks will be created using it to allow replayAll/verifyAll to work afterwards
But when using delegation, the parameter (i.e. the test class) doesn't extend EasyMockSupport
. Is there something I'm missing or is it impossible?
Side note: I'm using EasyMock 3.6. Ideally I'd like to find a solution keeping that version, but feel free to indicate if there is a related feature/bugfix in a later release.
Thanks in advance for your help!
答案1
得分: 1
不容易。但是这是一个有用的用例,所以我建议您提交一个 问题。
与此同时,我们需要让规则意识到 EasyMocksSupport。下面是一个解决方案。
import org.easymock.EasyMock;
import org.easymock.EasyMockRule;
import org.easymock.EasyMockSupport;
import org.easymock.Mock;
import org.easymock.TestSubject;
import org.easymock.internal.MocksControl;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import java.lang.reflect.Field;
// 被测试的类
class MyClass {
private Collaborator collaborator;
public MyClass() {
collaborator = new Collaborator();
}
// 待测试的方法
public int myMethod() {
return collaborator.mockedMethod() + 1;
}
}
// 待模拟的类
class Collaborator {
public int mockedMethod() {
return 1;
}
}
class ExtendedEasyMockSupport extends EasyMockSupport {
public void addMock(Object mock) {
if (EasyMockSupport.getMockedClass(mock) == null) {
throw new IllegalArgumentException(mock + " 不是一个模拟对象");
}
MocksControl control = MocksControl.getControl(mock);
controls.add(control);
}
public void addAllMocks(Object testClass) {
Field[] fields = testClass.getClass().getDeclaredFields();
for (Field field : fields) {
Mock annotation = field.getAnnotation(Mock.class);
if (annotation != null) {
field.setAccessible(true);
Object mock;
try {
mock = field.get(testClass);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
addMock(mock);
}
}
}
}
// 测试用例
public class MyClassTest {
private final ExtendedEasyMockSupport easyMockSupport = new ExtendedEasyMockSupport();
@Rule
public EasyMockRule easyMockRule = new EasyMockRule(this);
@TestSubject
private final MyClass testSubject = new MyClass();
@Mock
private Collaborator collaboratorMock;
@Before
public void before() {
easyMockSupport.addAllMocks(this);
}
@Test
public void testMyMethod() {
EasyMock.expect(collaboratorMock.mockedMethod()).andReturn(2);
easyMockSupport.replayAll();
int result = testSubject.myMethod();
Assert.assertEquals("成功模拟时应返回 2+1", 3, result);
// 抛出 java.lang.AssertionError: 期望值: <3> 实际值: <1>
}
}
英文:
Not easily. However it's a useful use-case so I recommend the you fill an issue.
Meanwhile, we need to make the rule aware of the EasyMocksSupport. Here is a solution.
import org.easymock.EasyMock;
import org.easymock.EasyMockRule;
import org.easymock.EasyMockSupport;
import org.easymock.Mock;
import org.easymock.TestSubject;
import org.easymock.internal.MocksControl;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import java.lang.reflect.Field;
// Class under test
class MyClass {
private Collaborator collaborator;
public MyClass() {
collaborator = new Collaborator();
}
// Method under test
public int myMethod() {
return collaborator.mockedMethod() + 1;
}
}
// Class to be mocked
class Collaborator {
public int mockedMethod() {
return 1;
}
}
class ExtendedEasyMockSupport extends EasyMockSupport {
public void addMock(Object mock) {
if(EasyMockSupport.getMockedClass(mock) == null) {
throw new IllegalArgumentException(mock + " is not a mock");
}
MocksControl control = MocksControl.getControl(mock);
controls.add(control);
}
public void addAllMocks(Object testClass) {
Field[] fields = testClass.getClass().getDeclaredFields();
for (Field field : fields) {
Mock annotation = field.getAnnotation(Mock.class);
if(annotation != null) {
field.setAccessible(true);
Object mock;
try {
mock = field.get(testClass);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
addMock(mock);
}
}
}
}
// Test case
public class MyClassTest {
private final ExtendedEasyMockSupport easyMockSupport = new ExtendedEasyMockSupport();
@Rule
public EasyMockRule easyMockRule = new EasyMockRule(this);
@TestSubject
private final MyClass testSubject = new MyClass();
@Mock
private Collaborator collaboratorMock;
@Before
public void before() {
easyMockSupport.addAllMocks(this);
}
@Test
public void testMyMethod() {
EasyMock.expect(collaboratorMock.mockedMethod()).andReturn(2);
easyMockSupport.replayAll();
int result = testSubject.myMethod();
Assert.assertEquals("Should return 2+1 when successfully mocked", 3, result);
// throws java.lang.AssertionError: expected: <3> but was: <1>
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论