Как использовать EasyMockSupport через делегирование с EasyMockRule или EasyMockRunner? - PullRequest
0 голосов
/ 04 мая 2020

Можно ли использовать как EasyMockSupport, так и EasyMockRule (или EasyMockRunner) при использовании делегирования от EasyMockSupport до (вместо наследования)?

Другими словами: как заставить EasyMockSupport знать о имитациях, созданных EasyMockRule?

Вот MWE, демонстрирующее проблему, с которой я сталкиваюсь 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>
    }
}

Тест не пройден, тогда как он проходит, если MyClassTest расширяется EasyMockSupport. (Но я не могу использовать наследование для того, что я делаю, поэтому мой вопрос.)

Мое понимание этого поведения заключается в том, что в моем примере EasyMockSupport не знает о Collaborator mock, поэтому вызов replayAll() не имеет никакого эффекта, и mock все еще находится в состоянии записи при вызове в testSubject.myMethod() (таким образом mockedMethod() возвращает 0). Действительно, injectMocks() документация гласит:

Если параметр расширяет EasyMockSupport, с его помощью будут создаваться насмешки, чтобы впоследствии можно было использовать replayAll / verifyAll

Но при использовании делегирования параметр (т. Е. Класс тестирования) не расширяется EasyMockSupport. Я что-то упускаю или это невозможно?

Примечание: я использую EasyMock 3.6. В идеале я хотел бы найти решение, сохраняющее эту версию, но не стесняйтесь указывать, есть ли связанная функция / исправление в более позднем выпуске.

Заранее спасибо за вашу помощь!

1 Ответ

1 голос
/ 06 мая 2020

не легко. Однако это полезный вариант использования, поэтому я рекомендую вам заполнить вопрос .

. Тем временем нам нужно проинформировать правило о 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 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>
    }
}
...