Модульное тестирование класса с автопроводной нотацией с использованием Junit и EasyMock? - PullRequest
27 голосов
/ 21 марта 2012

Я пытаюсь написать модульный тест для класса, несколько полей которого помечены как @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(){
    //??????
  } 

}

Будет здорово получить толчок в правильном направлении.

Спасибо

Ответы [ 3 ]

34 голосов
/ 21 марта 2012

Вы можете отражающим образом вводить зависимости непосредственно в поле, используя ReflectionTestUtils, например,

ReflectionTestUtils.setField( testInstance, "fieldName", fieldValue );

Некоторые утверждают, что в любом случае предпочтительнее добавить в класс видимый для пакета метод установки, используемый исключительно в тестах. В качестве альтернативы используйте конструкторы с автопроводкой, а не поля с автопроводкой и вставьте в них тестовые зависимости.

6 голосов
/ 21 марта 2012

Хотя можно установить эти поля с помощью отражения, это не позволит вашим инструментам разработки найти использование этих полей и затруднит вам рефакторинг SomeClassToTest в будущем.

Было бы лучше добавить общедоступные сеттеры для этих полей и вместо них поместить аннотации @Autowired. Это не только позволяет избежать отражения, но также проясняет внешний интерфейс класса и гарантирует, что ваш модульный тест использует только этот интерфейс. Я вижу, что SomeClassToTest уже реализует интерфейс SomeOtherClass, и я предполагаю, что клиенты SomeClassToTest используют только этот интерфейс, поэтому нет никакой опасности делать сеттеры на SomeClassToTest общедоступными.

Еще лучше, используйте инжектор конструктора и сделайте поля окончательными. Вы все еще можете использовать @Autowired в качестве аргументов конструктора.

2 голосов
/ 08 декабря 2015

Я не рекомендую ответ, который был принят, т. Е. Использовать рефлексию самостоятельно (без насмешливых рамок).

Начиная с версии 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");
  }
}
...