2016-10-07 5 views
1

У меня проходит единичный тест, но я не знаю, почему его работа. Установка точек отладки в IntelliJ показывает, что свойство Autowired равно нулю. Я опубликовал проект на GitHub, если кто-то хочет посмотреть: https://github.com/leonj1/spring_sparkНе знаете, почему этот модульный тест работает. Spring ConfigurationContext обновление или создание нового объекта?

Ниже приведен код, где я прокомментировал точки отладки (например, # 1, # 2, # 3). Когда удаляемая точка # 1 + # 2 получает удар, @Autowired PersonRoute personRoute всегда имеет значение null. Вероятно, это связано с тем, что внутренний статический класс создается после @ContextConfiguration синтаксический анализ @Configuration.

Но тогда как testServer в @ClassRule получить регидратацию SimpleController? Я знаю, что Spring использует Reflections для проверки и установки свойств, но для меня это будет новостью, если она также делает это для объектов, которые уже созданы.

Я пытаюсь понять это, потому что в настоящий момент не зная, что у меня меньше доверия к тесту.

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration 
@TestExecutionListeners({ 
     DependencyInjectionTestExecutionListener.class, 
     DbUnitTestExecutionListener.class 
}) 
@DatabaseSetup("persons-entities.xml") 
@Transactional 
public class SimpleControllerTest { 

    @Configuration 
    @ComponentScan(basePackages = {"com.jose.sandbox"}) 
    static class SomeConfig { 

     // because @PropertySource doesn't work in annotation only land 
     @Bean 
     public PropertyPlaceholderConfigurer propConfig() { 
      // #3 debug point 3, then shows Spring creating beans 
      // but how does SimpleController.class get the property set? 
      // does this mean 2 different SimpleController objects exist in the JVM, but only one is "wired"? 
      PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer(); 
      ppc.setLocation(new ClassPathResource("application.properties")); 
      return ppc; 
     } 
    } 

    @Component 
    public static class TestControllerTestApplication implements SparkApplication { 

     // #1 debug point 1 in IDE shows this as NULL 
     @Autowired PersonRoute personRoute; 

     @Override 
     public void init() { 
      new SimpleController(this.personRoute); 
     } 
    } 

    @ClassRule 
    public static SparkServer<SimpleControllerTest.TestControllerTestApplication> testServer 
      = new SparkServer<>(SimpleControllerTest.TestControllerTestApplication.class, 4567); 

    @Test 
    public void verifyGetAllPeople() throws Exception { 
     // given 
     String payload = null; 

     // when 
     SparkClient.UrlResponse response = testServer.getClient().doMethod("GET", "/people/count", payload); 

     // then 
     int expected = 3; // because that's how many exist in persons-entities.xml 
     assertEquals(200, response.status); 
     assertEquals(expected, Integer.parseInt(response.body)); 
     assertNotNull(testServer.getApplication()); 
    } 

    @Mock 
    Response response; 
} 

Вот контроллер, который начальная точка отладки показывает NULL для Autowired свойства. Точка отладки никогда не будет ударяться снова, так как это устанавливается?

@Component 
public class SimpleController { 

    // #2 debug point 2, also shows this as NULL 
    @Autowired PersonRoute personRoute; 

    public SimpleController() {} 

    public SimpleController(PersonRoute personRoute) { 
     this.personRoute = personRoute; 
    } 

    @PostConstruct 
    public void init() { 
     get("/people/count", this.personRoute); 
    } 
} 

Любая помощь была бы оценена, так как это трудно было построить на этом тесте, пока не будет понят.

+0

Кстати, это не юнит тест. Это интеграционный тест. –

+0

Кроме того, 'PropertyPlaceholderConfigurer' должен быть' static'. Подробнее см. В Javadoc для '@ Bean'. –

+0

И ... присутствие '@ Transactional' бессмысленно в вашем примере, так как вы не регистрируете' TransactionalTestExecutionListener'. Рассмотрим только объявление слушателя DbUnit и использование 'MERGE_WITH_DEFAULTS' как' mergeMode' с '@TestExecutionListeners (...)'. –

ответ

2

Но тогда как же testServer в @ClassRule получить регидратированного SimpleController?

Это не так.

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

// @Component 
public static class TestControllerTestApplication implements SparkApplication { 

    // #1 debug point 1 in IDE shows this as NULL 
    // @Autowired PersonRoute personRoute; 

    @Override 
    public void init() { 
     // new SimpleController(this.personRoute); 
    } 
} 

Вот контроллер, который начальная точка отладки показывает NULL для Autowired свойства. Точка отладки никогда не будет ударяться снова, так как это устанавливается?

Весна вводит @Autowired PersonRoute в SimpleController с использованием отражения.

В основном, что происходит, следующее.

  1. Вы поручаете Spring для выполнения сканирования компонентов, начиная с com.jose.sandbox базового пакета, который приводит к полной инициализации PersonRepository, PersonRoute и SimpleController бобы.
  2. Фасоль PersonRoute вводится в фасоль SimpleController.
  3. Метод bean получает вызванный весной, так как вы его аннотировали @PostConstruct и регистрируете маршрут с помощью Spark через статический вызов метода get(...).
  4. Рамка проверки искры затем создает ваш TestControllerTestApplication во время фазы «перед классом» для правила JUnit 4, но маршрут уже зарегистрирован. Таким образом, нет необходимости в вашем TestControllerTestApplication, чтобы фактически что-либо сделать. Вот почему я прокомментировал приведенный выше код.

Другими словами, вам нужно всего лишь пустой TestControllerTestApplication реализации, поскольку SparkServer из рамок искрообразующего требует. Без весны было бы разумно реализовать это, но из-за того, как вы настроили вещи с помощью Spring, нет необходимости в реализовать.

Надеюсь, это разъяснит вам все.

С уважением,

Сэм (автор Spring Framework TestContext)