Как получить доступ к объекту Spring @Service из теста jUnit

Ситуация: у меня есть класс реализации службы, аннотированный @Service с доступом к файлу свойств.

@Service("myService")
public class MySystemServiceImpl implements SystemService{

      @Resource
      private Properties appProperties;

}

Объект Properties настраивается через config-файл. applicationContext.xml

<util:properties id="appProperties" location="classpath:application.properties"/>

Я хочу протестировать некоторые методы этой реализации.

Вопрос: Как получить доступ к MySystemServiceImpl-объекту из тестового класса таким образом, чтобы свойства appProperties были правильно инициализированы?

public class MySystemServiceImplTest {

    //HOW TO INITIALIZE PROPERLY THROUGH SPRING? 
    MySystemServiceImpl testSubject;

    @Test
    public void methodToTest(){
        Assert.assertNotNull(testSubject.methodToTest());
    }     

}

Я не могу просто создать новый MySystemServiceImpl - чем методы, использующие appProperties, выдают исключение NullPointerException. И я не могу напрямую вводить свойства в объект - нет подходящего сеттера-метода.

Просто укажите здесь правильные шаги (спасибо @NimChimpsky за ответ):

  1. Я скопировал application.properties в папку test/resources.

  2. Я скопировал applicationContext.xml в каталог test/resources. В контексте приложения я добавляю новый компонент (определение свойств приложения уже здесь):

    <bean id="testSubject" class="com.package.MySystemServiceImpl">
    
  3. Я изменил тестовый класс таким образом:

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations={"/applicationContext.xml"})
    public class MySystemServiceImplTest {
    
       @Autowired
       MySystemServiceImpl testSubject;
    
    }
    
  4. И это делает трюк - теперь в моем тестовом классе доступен полностью функциональный объект


person dim1902    schedule 11.10.2011    source источник


Ответы (2)


В качестве альтернативы, чтобы выполнить интеграционный тест, я делаю это.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"/applicationContext-test.xml"})
@Transactional
public class MyTest {

    @Resource(name="myService")
    public IMyService myService;

Затем используйте сервис как обычно. Добавьте контекст приложения в каталог test/resources.

person NimChimpsky    schedule 11.10.2011

Просто используйте его конструктор:

MySystemServiceImpl testSubject = new MySystemServiceImpl();

Это модульный тест. Модульный тест проверяет класс отдельно от других классов и от инфраструктуры.

Если у вашего класса есть зависимости от других интерфейсов, смоделируйте эти интерфейсы и создайте объект с этими макетами в качестве аргумента. В этом весь смысл внедрения зависимостей: возможность внедрить другие, фиктивные реализации внутри объекта, чтобы легко протестировать этот объект.

ИЗМЕНИТЬ:

Вы должны предоставить установщик для вашего объекта свойств, чтобы иметь возможность вводить свойства, которые вы хотите для каждого из модульных тестов. Внедренные свойства могут содержать номинальные значения, экстремальные значения или неверные значения в зависимости от того, что вы хотите протестировать. Внедрение полей практично, но не очень хорошо подходит для модульного тестирования. Внедрение конструктора или сеттера следует отдавать предпочтение при использовании модульного тестирования, потому что основная цель внедрения зависимостей как раз и состоит в том, чтобы иметь возможность внедрять фиктивные или конкретные зависимости в модульные тесты.

person JB Nizet    schedule 11.10.2011
comment
К сожалению, у меня нет возможности изменить класс. Вот почему я должен придерживаться Spring инъекции. Во всем остальном согласен с вашей точкой зрения - person dim1902; 11.10.2011
comment
Есть ли недостатки в отказе от инъекций? - person cellepo; 28.05.2019