учебник по транзакциям - тестовый откат

Я пытаюсь научиться использовать транзакцию в java spring. Я новичок в Java, поэтому, пожалуйста, потерпите меня :-) Модульный тест, который я пытаюсь выполнить ниже, - это тестирование: откат, если выдается исключение во время выполнения.

У меня проблема с java.lang.NullPointerException?

Хорошо, вот. Я удалил часть кода, чтобы улучшить читаемость

TutorialTest.java

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AppConfig.class, loader=AnnotationConfigContextLoader.class)
public class TutorialTest {

    @Autowired
    private Dao dao;


    @Test
    public void that_if_a_runtime_exception_is_thrown_transaction_rolledback(){

        User u = new User();
        u.setUsername("FAIL_TEST");
        u.setPhone("0161");
        u.setEmail("[email protected]");
        //dao.addUser(u);  // -- this will insert if uncommented out so I know it works

        OuterService os  = new OuterService();
        os.addUserThrowError(u);

    }
}

OuterService.java

@ContextConfiguration(classes = AppConfig.class, loader=AnnotationConfigContextLoader.class)
public class OuterService {

    @Autowired
    private Dao dao;

    @Transactional
    public void addUserThrowError(User user) throws RuntimeException{

        dao.addUser(user);  // gives me a java.lang.NullPointerException?

        throw new RuntimeException("This should roll back DB entry");
    }

}

Бобы объявлены в

AppConfig.java

@Configuration
@EnableTransactionManagement
@ComponentScan(value = {"com.training.spring.tx.tutorial.dao",
                        "com.training.spring.tx.tutorial.service"})
public class AppConfig {

    public DataSource dataSource() {

        // Create a BasicDataSource object and configure database

        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost/spring_training_tx");
        dataSource.setUsername("training");
        dataSource.setPassword("training");

        return dataSource;
    }

    @Bean
    public DataSourceTransactionManager transactionManager() {
        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
        transactionManager.setDataSource(dataSource());
        return transactionManager;
    }

    @Bean
    public JdbcTemplate jdbcTemplate(){
        return new JdbcTemplate(transactionManager().getDataSource());
    }

}

person Robbo_UK    schedule 13.05.2014    source источник
comment
Весна не участвует в new OuterService();   -  person Sotirios Delimanolis    schedule 13.05.2014
comment
Загляните в Javadoc. Spring имеет очень хорошую документацию. Что делает @ContextConfiguration? Как вы объявляете бобы весной?   -  person Sotirios Delimanolis    schedule 13.05.2014
comment
Привет, я обновил вопрос, чтобы помочь улучшить его. Я также убрал весну из названия. Я включил объявление бобов.   -  person Robbo_UK    schedule 13.05.2014
comment
Ответ чрезвычайно прост: Spring не участвует в new OuterService(); и, следовательно, ничего не подключает к этому объекту автоматически. Объяснение длиннее. Прочтите документацию Spring IoC, в которой все это объясняется.   -  person Sotirios Delimanolis    schedule 13.05.2014
comment
Я просмотрел документацию, и я не приблизился к выяснению того, что мне нужно делать? Из ваших ответов я понял, что мне нужно связать new OuterService() с конфигурацией bean-компонентов. Примеры bean-компонентов находятся в XML, а те, которые мне сказали изучить, - нет.   -  person Robbo_UK    schedule 13.05.2014


Ответы (1)


Прежде всего, процитируем javadoc из @ContextConfiguration

@ContextConfiguration определяет метаданные уровня класса, которые используются для определения того, как загружать и настраивать ApplicationContext для интеграционных тестов.

Подумайте, как вы используете его на OuterService. Это кажется правильным? Предназначен ли OuterService для загрузки и настройки ApplicationCOntext для интеграционных тестов? Если я не упустил что-то существенное, ответ: нет.

Так что же такое OuterService? Это какая-то услуга. Кажется, вы хотите использовать его как боб. Что такое боб? Компонент — это объект, жизненным циклом которого управляет Spring. Это включает создание экземпляра класса компонента, инициализацию объекта, постобработку и, наконец, уничтожение объекта.

Если вы создали объект так

OuterService os  = new OuterService();

тогда Весна не участвует. Вы создали объект, и Spring не может подключиться к нему. Поэтому вы не можете ожидать, что Spring автоматически подключит свое поле

@Autowired
private Dao dao;

И поскольку вы не инициализировали поле, оно остается null, что приводит к ошибке NullPointerException.

Итак, как нам получить bean-компонент OuterService, которым управляет Spring? Вы либо объявляете метод @Bean для OuterService, либо аннотируете OuterService с помощью @Component или любой из его специализаций и сканируете пакет, в котором он находится. Затем вы внедряете компонент в любой другой компонент, который его использует. Например,

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AppConfig.class, loader=AnnotationConfigContextLoader.class)
public class TutorialTest {

    @Autowired
    private Dao dao;

    @Autowired
    private OuterService os;

Затем вы можете использовать эту переменную напрямую.

person Sotirios Delimanolis    schedule 13.05.2014