Модуль тестирует класс с автоподзаводом с помощью Junit и EasyMock?
Я пытаюсь написать Unit test для класса, у которого есть несколько полей, помеченных @Autowired. Учитывая, что Spring автоматически разрешает конкретные реализации для этих полей, мне сложно определить, как подключить мои объекты Mock (созданные через EasyMock) в качестве зависимостей во время тестового запуска. Использование @Autowired в классе означает отсутствие сеттеров в этом классе. Есть ли способ для меня подключить мои макетные объекты, не создавая дополнительных настроек в классе?
Вот пример того, что я пытаюсь выполнить:
public class SomeClassUnderTest implements SomeOtherClass{
@Autowired
private SomeType someType;
@Autowired
private SomeOtherType someOtherType;
@Override
public SomeReturnType someMethodIWouldLikeToTest(){
//Uses someType and someOtherType and returns SomeReturnType
}
}
Вот как я создаю свой тестовый класс, прежде чем ударить по стене:
public class MyTestClassForSomeClassUnderTest{
private SomeType someType;
private SomeOtherType someOtherType;
@Before
public void testSetUp(){
SomeClassUnderTest someClassToTest = new SomeClassUnderTest();
someType = EasyMock.createMock(SomeType.class);
someOtherType = EasyMock.createMock(SomeOtherType.class);
//How to set dependencies????
}
@Test
public void TestSomeMethodIWouldLikeToTest(){
//??????
}
}
Будет здорово получить толчок в правильном направлении.
Спасибо
Ответы
Ответ 1
Вы можете отражать зависимости непосредственно в поле, используя ReflectionTestUtils
, например
ReflectionTestUtils.setField( testInstance, "fieldName", fieldValue );
Некоторые утверждают, что предпочтительнее добавлять в класс методу set-view setter, используемому исключительно в тестах. В качестве альтернативы, используйте конструкторы с автосозданием, а не поля с автосогласованием, и вставляйте в них тестовые зависимости.
Ответ 2
Несмотря на то, что эти поля можно настроить с помощью отражения, это не позволит вашим инструментам разработки искать способы использования этих полей и затрудняет реорганизацию SomeClassToTest
в будущем.
Было бы лучше добавить публичные сеттеры для этих полей и разместить вместо них аннотации @Autowired
. Это не только позволяет избежать отражения, но также разъясняет внешний интерфейс класса и гарантирует, что ваш unit test использует только этот интерфейс. Я вижу, что SomeClassToTest
уже реализует интерфейс SomeOtherClass
, и я предполагаю, что клиенты SomeClassToTest
используют этот интерфейс, поэтому существует небольшая опасность сделать публикаторы на SomeClassToTest
общедоступными.
Еще лучше, используйте инъекцию конструктора и сделайте поля окончательными. Вы все еще можете использовать @Autowired
в аргументах конструктора.
Ответ 3
Я не рекомендую ответ, который был принят, т.е. используя отражение самостоятельно (без насмешливой структуры).
Начиная с версии 3.2 EasyMock вы можете использовать аннотации, чтобы определять макеты и вводить их в тестируемый класс. Полное описание, как это сделать, можно найти в официальной документации EasyMock:
http://easymock.org/user-guide.html#mocking-annotations
Вот пример из вышеупомянутого сайта:
import static org.easymock.EasyMock.*;
import org.easymock.EasyMockRunner;
import org.easymock.TestSubject;
import org.easymock.Mock;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(EasyMockRunner.class)
public class ExampleTest {
@TestSubject
private ClassUnderTest classUnderTest = new ClassUnderTest(); // 2
@Mock
private Collaborator mock; // 1
@Test
public void testRemoveNonExistingDocument() {
replay(mock);
classUnderTest.removeDocument("Does not exist");
}
}