Весенние тесты: транзакция не откатывается после выполнения метода тестирования - PullRequest
2 голосов
/ 14 января 2010

Я пытаюсь создать интеграционные тесты для устаревшего приложения, развернутого в Weblogic 8.1 с использованием подкласса AbstractTransactionalJUnit4SpringContextTests.

Мой метод испытаний имеет следующие аннотации:

@Test
@Rollback(true)
public void testDeployedEJBCall throws Exception {...}

Мой тестовый класс также ссылается на bean-компоненты типа org.springframework.ejb.access.SimpleRemoteStatelessSessionProxyFactoryBean, которые проксируют EJB-компоненты, развернутые на моем веб-логическом сервере.

Когда я последовательно вызываю методы для этого прокси-компонента в моем тестовом методе, транзакция корректно откатывается в конце теста.

например. :

@Test
@Rollback(true)
public void testDeployedEJBCall throws Exception {
    Long result1 = myejb.method(100L);
    Long result2 = myejb.method(200L);
    ...
}

Однако я хотел бы сделать 2 параллельных вызова одного и того же метода EJB. Поэтому я создал внутренний класс, который реализует Callable, чтобы вызывать мои методы в 2 разных потоках и надеюсь запустить их параллельно.
Однако выполнение этого, кажется, делает методы ejb вызываемыми вне моей транзакции, и ничего не откатывается.

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

import org.springframework.test.annotation.*;

@RunWith(SpringJUnit4ClassRunner.class)
@Transactional
@ContextConfiguration(locations = {"classpath:path/to/tests-config.xml"})
@TransactionConfiguration(defaultRollback=true)
public final class IntegrationTests extends AbstractTransactionalJUnit4SpringContextTests {
    @Autowired
    protected JndiTemplate jndiTemplate;
    @Resource
    protected Proxy myEJB;

    public IntegrationTests() {
        super();
        this.logger = Logger.getLogger(IntegrationTests.class);
    }

    @Test
    @Rollback(true)
    public void testDeployedEJBCall() throws Exception {
        // Create a thread pool for parallel execution. 
        ExecutorService exec = Executors.newFixedThreadPool(2);

        // Prepare the tasks for parallel execution
        List<CallEJBTask> tasks = new ArrayList<CallEJBTask>();
        tasks.add(new CallEJBTask(100L, this.myEJB));
        tasks.add(new CallEJBTask(200L, this.myEJB));

        // Execute all pending tasks in the exec Threadpool
        List<Future<Long>> results = exec.invokeAll(tasks);

        // Get the results of each task
        Long result1 = results.get(0).get();
        Long result2 = results.get(1).get();

        ...
    }
}

private class CallEBJTask implements Callable<Long> {
    private final Long valueToTest;
    private final MyEJB myEJB;

    public CallEJBTask(Long valueToTest, Proxy myEJBProxy)
        this.valueToTest = valueToTest;
        this.myEJB = (MyEJB)myEJBProxy;
    }

    public Long call() throws Exception {
        return getResult();
    }

    public Long getResult() {
        Long result = null;

        try {
            result = this.myEJB.method(this.patient);

        } catch (Exception e) {
            ...
        }
        return result;   
    } 
}

Есть ли способ сделать этот откат ???

Спасибо за вашу помощь.

С уважением,

Philippe

1 Ответ

2 голосов
/ 14 января 2010

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

Какова цель двух параллельных казней? При таком подходе вы вряд ли сможете проверить наличие проблем параллелизма, если вы к этому стремитесь.

Редактировать: Проблема в том, что тестирование на проблемы параллелизма очень сложно, потому что ваши тесты, в лучшем случае, вероятностные - успех или неудача зависят от тонких проблем синхронизации, которые могут возникнуть только на миллиардном прогоне. См. эту статью о серверной стороне , где содержится краткое изложение основ.

Эмпирическое правило должно заключаться в том, чтобы по возможности избегать ручного кодирования, так как его трудно получить правильно и сложно проверить. Если можете, избегайте общего состояния между потоками и, если нет пути к нему, полагайтесь на параллельные структуры данных и асинхронные исполнители из пакета java.util.concurrent.

...