├── src
├── test
│ ├── resources
│ │ ├── META-INF
│ │ │ ├── beans.xml
│ │ │ └── persistence.xml
│ │ └── simplelogger.properties
│ └── java
│ │ └── info
│ │ └── novatec
│ │ └── beantest
│ │ └── demo
│ │ ├── ejb
│ │ ├── DeltaSpikeSingletonInjectionTest.java
│ │ ├── DeltaSpikePersistenceExceptionPropagationTest.java
│ │ ├── DeltaSpikeMockProducerTest.java
│ │ ├── MyEjbServiceThatCallsAnExternalService.java
│ │ ├── MyEJBServiceWithEntityManagerSetter.java
│ │ ├── MyExternalService.java
│ │ ├── MyEjbSingleton.java
│ │ ├── DeltaSpikeRollbackExceptionTest.java
│ │ ├── TestSingletonInjection.java
│ │ ├── TestPersistenceExceptionPropagation.java
│ │ ├── TestExternalServices.java
│ │ ├── MyOtherEJBService.java
│ │ ├── TestNoRollbackException.java
│ │ ├── DeltaSpikeEjbJpaTest.java
│ │ ├── TestEJBInjection.java
│ │ └── MyEJBService.java
│ │ ├── exceptions
│ │ └── MyException.java
│ │ ├── mocks
│ │ └── ExternalServicesMockProducer.java
│ │ └── entities
│ │ ├── MyEntity.java
│ │ └── MyEntityWithConstraints.java
└── main
│ ├── resources
│ └── META-INF
│ │ ├── services
│ │ └── javax.enterprise.inject.spi.Extension
│ │ └── beans.xml
│ └── java
│ └── info
│ └── novatec
│ └── beantest
│ ├── api
│ ├── CdiContainerShutdown.java
│ ├── BaseBeanTest.java
│ └── BeanProviderHelper.java
│ ├── transactions
│ ├── Transactional.java
│ └── TransactionalInterceptor.java
│ ├── extension
│ ├── AnnotationInstances.java
│ ├── InjectionHelper.java
│ └── BeanTestExtension.java
│ └── producers
│ └── EntityManagerProducer.java
├── .travis.yml
├── .gitignore
├── NOTICE.txt
├── .github
└── workflows
│ └── maven-publish.yml
├── README.md
├── pom.xml
└── LICENSE
/src/test/resources/META-INF/beans.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: java
2 | jdk:
3 | - oraclejdk7
4 |
--------------------------------------------------------------------------------
/src/test/resources/simplelogger.properties:
--------------------------------------------------------------------------------
1 | org.slf4j.simpleLogger.log.info.novatec=debug
--------------------------------------------------------------------------------
/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension:
--------------------------------------------------------------------------------
1 | info.novatec.beantest.extension.BeanTestExtension
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | target/
2 | .project
3 | .classpath
4 | .settings/
5 | nb-configuration.xml
6 | *.log
7 | *.versionsBackup
8 | .vscode/
--------------------------------------------------------------------------------
/src/main/resources/META-INF/beans.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 | info.novatec.beantest.transactions.TransactionalInterceptor
9 |
10 |
11 |
--------------------------------------------------------------------------------
/NOTICE.txt:
--------------------------------------------------------------------------------
1 | Bean Testing
2 | Copyright 2013 NovaTec GmbH.
3 |
4 | This product includes software developed for NovaTec Consulting GmbH
5 |
6 | This product includes software from:
7 |
8 | Simple Logging Facade for Java (SLF4J) (http://www.slf4j.org/) under the MIT License.
9 | Apache Deltaspike (http://deltaspike.apache.org/) under the Apache License 2.0.
10 | JBoss Weld (http://weld.cdi-spec.org/) under the Apache Licesne 2.0.
11 | Junit (http://junit.org/) under the Eclipse Public License 1.0.
12 | Mockito (https://code.google.com/p/mockito/) under the MIT License.
13 | Hamcrest (https://code.google.com/p/hamcrest/) under the BSD License.
14 |
--------------------------------------------------------------------------------
/src/test/java/info/novatec/beantest/demo/ejb/DeltaSpikeSingletonInjectionTest.java:
--------------------------------------------------------------------------------
1 | package info.novatec.beantest.demo.ejb;
2 |
3 | import org.apache.deltaspike.testcontrol.api.junit.CdiTestRunner;
4 | import org.junit.Test;
5 | import org.junit.runner.RunWith;
6 |
7 | import javax.inject.Inject;
8 |
9 | import static org.hamcrest.Matchers.is;
10 | import static org.junit.Assert.assertThat;
11 |
12 | @RunWith(CdiTestRunner.class)
13 | public class DeltaSpikeSingletonInjectionTest {
14 |
15 | @Inject
16 | private MyEjbSingleton singleton;
17 |
18 | @Test
19 | public void shouldBeInstantiatedOnce() {
20 | assertThat(singleton.wasEjbCalled(), is(false));
21 | singleton.callAnEjb();
22 | assertThat(singleton.wasEjbCalled(), is(true));
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/info/novatec/beantest/api/CdiContainerShutdown.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Bean Testing.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package info.novatec.beantest.api;
18 |
19 | /**
20 | * Represents a CDI container shutdown event.
21 | *
22 | * This event will be fired when the CDI container is about to shutdown.
23 | *
24 | * @author Carlos Barragan (carlos.barragan@novatec-gmbh.de)
25 | */
26 | public class CdiContainerShutdown {
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/src/test/java/info/novatec/beantest/demo/exceptions/MyException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Bean Testing.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package info.novatec.beantest.demo.exceptions;
18 |
19 | /**
20 | * Demo Exception.
21 | *
22 | * @author Carlos Barragan (carlos.barragan@novatec-gmbh.de)
23 | */
24 | public class MyException extends RuntimeException {
25 |
26 | public MyException(String message) {
27 | super(message);
28 | }
29 |
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/src/test/java/info/novatec/beantest/demo/ejb/DeltaSpikePersistenceExceptionPropagationTest.java:
--------------------------------------------------------------------------------
1 | package info.novatec.beantest.demo.ejb;
2 |
3 | import info.novatec.beantest.demo.entities.MyEntityWithConstraints;
4 | import org.apache.deltaspike.testcontrol.api.junit.CdiTestRunner;
5 | import org.junit.Test;
6 | import org.junit.runner.RunWith;
7 |
8 | import javax.inject.Inject;
9 | import javax.persistence.PersistenceException;
10 |
11 | import static org.junit.Assert.fail;
12 |
13 | @RunWith(CdiTestRunner.class)
14 | public class DeltaSpikePersistenceExceptionPropagationTest {
15 |
16 | @Inject
17 | private MyEJBService myEJBService;
18 |
19 | @Test(expected = PersistenceException.class)
20 | public void shouldCauseExceptionBecuaseUniquenessViolation() {
21 | MyEntityWithConstraints entity = new MyEntityWithConstraints("123");
22 | myEJBService.save(entity);
23 | entity = new MyEntityWithConstraints("123");
24 | myEJBService.save(entity);
25 | fail("Should have failed because uniqueness violation");
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/src/test/java/info/novatec/beantest/demo/ejb/DeltaSpikeMockProducerTest.java:
--------------------------------------------------------------------------------
1 | package info.novatec.beantest.demo.ejb;
2 |
3 | import info.novatec.beantest.demo.mocks.ExternalServicesMockProducer;
4 | import org.apache.deltaspike.testcontrol.api.junit.CdiTestRunner;
5 | import org.junit.Test;
6 | import org.junit.runner.RunWith;
7 | import org.mockito.Mockito;
8 |
9 | import javax.inject.Inject;
10 |
11 | import static org.hamcrest.CoreMatchers.is;
12 | import static org.junit.Assert.assertThat;
13 |
14 | @RunWith(CdiTestRunner.class)
15 | public class DeltaSpikeMockProducerTest {
16 |
17 | @Inject
18 | private MyEjbServiceThatCallsAnExternalService service;
19 |
20 | @Test
21 | public void shouldCallExternalServiceMock() {
22 | MyExternalService externalService = ExternalServicesMockProducer.getExternalService();
23 | //Since the ExternalServicesMockProducer returns a Mockito mock, we can initialize it
24 | Mockito.when(externalService.doSomething()).thenReturn("Hello World");
25 |
26 | assertThat(service.callExternalService(), is("Hello World"));
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/.github/workflows/maven-publish.yml:
--------------------------------------------------------------------------------
1 | # This workflow will build a package using Maven and then publish it to GitHub packages when a release is created
2 | # For more information see: https://github.com/actions/setup-java/blob/main/docs/advanced-usage.md#apache-maven-with-a-settings-path
3 |
4 | name: Maven Package
5 |
6 | on:
7 | release:
8 | types: [created]
9 |
10 | jobs:
11 | build:
12 |
13 | runs-on: ubuntu-latest
14 | permissions:
15 | contents: read
16 | packages: write
17 |
18 | steps:
19 | - uses: actions/checkout@v3
20 | - name: Set up JDK 11
21 | uses: actions/setup-java@v3
22 | with:
23 | java-version: '11'
24 | distribution: 'temurin'
25 | server-id: github # Value of the distributionManagement/repository/id field of the pom.xml
26 | settings-path: ${{ github.workspace }} # location for the settings.xml file
27 |
28 | - name: Build with Maven
29 | run: mvn -B package --file pom.xml
30 |
31 | - name: Publish to GitHub Packages Apache Maven
32 | run: mvn deploy -s $GITHUB_WORKSPACE/settings.xml
33 | env:
34 | GITHUB_TOKEN: ${{ github.token }}
35 |
--------------------------------------------------------------------------------
/src/test/java/info/novatec/beantest/demo/ejb/MyEjbServiceThatCallsAnExternalService.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Bean Testing.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package info.novatec.beantest.demo.ejb;
18 |
19 | import javax.ejb.EJB;
20 | import javax.ejb.Stateless;
21 |
22 | /**
23 | *
24 | * @author Carlos Barragan (carlos.barragan@novatec-gmbh.de)
25 | */
26 | @Stateless
27 | public class MyEjbServiceThatCallsAnExternalService {
28 |
29 | @EJB
30 | MyExternalService externalService;
31 |
32 | public String callExternalService() {
33 | return externalService.doSomething();
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/src/test/java/info/novatec/beantest/demo/ejb/MyEJBServiceWithEntityManagerSetter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Bean Testing.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package info.novatec.beantest.demo.ejb;
17 |
18 | import javax.ejb.Stateless;
19 | import javax.persistence.EntityManager;
20 | import javax.persistence.PersistenceContext;
21 |
22 | @Stateless
23 | public class MyEJBServiceWithEntityManagerSetter {
24 |
25 | private EntityManager em;
26 |
27 | @PersistenceContext(unitName = "db2")
28 | public void setEm(EntityManager em) {
29 | this.em = em;
30 | }
31 |
32 | public EntityManager getEm() {
33 | return em;
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/src/test/resources/META-INF/persistence.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | jdbc/productionDS
7 |
8 |
9 |
10 | org.hibernate.ejb.HibernatePersistence
11 | info.novatec.beantest.demo.entities.MyEntity
12 | info.novatec.beantest.demo.entities.MyEntityWithConstraints
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/test/java/info/novatec/beantest/demo/ejb/MyExternalService.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Bean Testing.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package info.novatec.beantest.demo.ejb;
18 |
19 | /**
20 | * Represents an external service whose implementation is located somewhere else.
21 | *
22 | * It is common to have dependencies to external services or modules in a JEE Application.
23 | * Usually it is possible to access those external services via a shared interface. The implementation of
24 | * such interface is normally located in another module or application.
25 | * @author Carlos Barragan (carlos.barragan@novatec-gmbh.de)
26 | */
27 | public interface MyExternalService {
28 |
29 | String doSomething();
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/src/test/java/info/novatec/beantest/demo/ejb/MyEjbSingleton.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Bean Testing.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package info.novatec.beantest.demo.ejb;
17 |
18 | import javax.ejb.EJB;
19 | import javax.ejb.Singleton;
20 |
21 | /**
22 | * Demo EJB Singleton.
23 | * @author Carlos Barragan (carlos.barragan@novatec-gmbh.de)
24 | */
25 | @Singleton
26 | public class MyEjbSingleton {
27 |
28 | @EJB
29 | MyOtherEJBService ejbService;
30 |
31 | private boolean wasEjbCalled=false;
32 |
33 | public void callAnEjb() {
34 | ejbService.doSomething();
35 | wasEjbCalled = true;
36 | }
37 |
38 | public boolean wasEjbCalled() {
39 | return this.wasEjbCalled;
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/src/test/java/info/novatec/beantest/demo/mocks/ExternalServicesMockProducer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Bean Testing.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package info.novatec.beantest.demo.mocks;
18 |
19 | import info.novatec.beantest.demo.ejb.MyExternalService;
20 | import javax.enterprise.inject.Produces;
21 | import org.mockito.Mockito;
22 |
23 | /**
24 | * Creates Mockito mocks for external services.
25 | *
26 | * @author Carlos Barragan (carlos.barragan@novatec-gmbh.de)
27 | */
28 | public class ExternalServicesMockProducer {
29 |
30 | private static MyExternalService externalServiceMock=Mockito.mock(MyExternalService.class);
31 |
32 | @Produces
33 | public static MyExternalService getExternalService() {
34 | return externalServiceMock;
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/src/test/java/info/novatec/beantest/demo/ejb/DeltaSpikeRollbackExceptionTest.java:
--------------------------------------------------------------------------------
1 | package info.novatec.beantest.demo.ejb;
2 |
3 | import info.novatec.beantest.demo.entities.MyEntity;
4 | import org.apache.deltaspike.testcontrol.api.junit.CdiTestRunner;
5 | import org.junit.Test;
6 | import org.junit.runner.RunWith;
7 |
8 | import javax.inject.Inject;
9 | import javax.persistence.NoResultException;
10 |
11 | import static org.hamcrest.Matchers.*;
12 | import static org.junit.Assert.assertThat;
13 | import static org.junit.Assert.fail;
14 |
15 | @RunWith(CdiTestRunner.class)
16 | public class DeltaSpikeRollbackExceptionTest {
17 |
18 | @Inject
19 | private MyEJBService myEJBService;
20 |
21 | @Test
22 | public void shouldExceptionNoCauseRollback() {
23 | MyOtherEJBService myOtherEJBService = myEJBService.getOtherService2();
24 |
25 | assertThat(myOtherEJBService.getAllEntities(), hasSize(0));
26 |
27 | MyEntity entity = new MyEntity();
28 | entity.setName("some name");
29 | try {
30 | myEJBService.saveEntityAndCausePersistenceExceptionWithoutRollback(entity);
31 | fail("Should have thrown PersistenceException");
32 | } catch (NoResultException exception) {
33 | assertThat(exception, not(nullValue()));
34 | }
35 |
36 |
37 | //Entity should have been saved
38 | assertThat(myOtherEJBService.getAllEntities(), hasSize(1));
39 |
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/info/novatec/beantest/api/BaseBeanTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Bean Testing.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package info.novatec.beantest.api;
18 |
19 | import java.lang.annotation.Annotation;
20 | import org.junit.After;
21 | import org.junit.Before;
22 |
23 | /**
24 | * Base class for initializing the {@link BeanProviderHelper}
25 | *
26 | * @author Carlos Barragan (carlos.barragan@novatec-gmbh.de)
27 | */
28 | public abstract class BaseBeanTest {
29 |
30 | private BeanProviderHelper bm;
31 |
32 | @Before
33 | public void initilaize() {
34 | bm = BeanProviderHelper.getInstance();
35 | }
36 |
37 | @After
38 | public void cleanUp() {
39 | bm.shutdown();
40 | }
41 |
42 | protected T getBean(Class beanClass, Annotation... qualifiers) {
43 | return bm.getBean(beanClass, qualifiers);
44 | }
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/info/novatec/beantest/transactions/Transactional.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Bean Testing.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package info.novatec.beantest.transactions;
17 |
18 | import java.lang.annotation.ElementType;
19 | import java.lang.annotation.Retention;
20 | import java.lang.annotation.RetentionPolicy;
21 | import java.lang.annotation.Target;
22 | import javax.ejb.TransactionAttributeType;
23 | import javax.enterprise.util.Nonbinding;
24 | import javax.interceptor.InterceptorBinding;
25 |
26 | /**
27 | * Interceptor binding for transactions.
28 | *
29 | * @author Carlos Barragan (carlos.barragan@novatec-gmbh.de)
30 | */
31 | @InterceptorBinding
32 | @Target({ElementType.METHOD, ElementType.TYPE})
33 | @Retention(RetentionPolicy.RUNTIME)
34 | public @interface Transactional {
35 |
36 | @Nonbinding
37 | TransactionAttributeType transactionAttribute() default TransactionAttributeType.REQUIRED;
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/src/test/java/info/novatec/beantest/demo/ejb/TestSingletonInjection.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Bean Testing.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package info.novatec.beantest.demo.ejb;
17 |
18 | import info.novatec.beantest.api.BaseBeanTest;
19 | import static org.hamcrest.Matchers.is;
20 | import static org.junit.Assert.assertThat;
21 | import org.junit.Test;
22 |
23 | /**
24 | * This test verifies that an EJB Singleton is instantiated just once and is able to call other EJBs.
25 | *
26 | * @author Carlos Barragan (carlos.barragan@novatec-gmbh.de)
27 | */
28 | public class TestSingletonInjection extends BaseBeanTest {
29 |
30 | @Test
31 | public void shouldBeInstantiatedOnce() {
32 | MyEjbSingleton singleton= getBean(MyEjbSingleton.class);
33 | assertThat(singleton.wasEjbCalled(), is(false));
34 | singleton.callAnEjb();
35 | assertThat(singleton.wasEjbCalled(), is(true));
36 | }
37 |
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/src/test/java/info/novatec/beantest/demo/ejb/TestPersistenceExceptionPropagation.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Bean Testing.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package info.novatec.beantest.demo.ejb;
18 |
19 | import info.novatec.beantest.api.BaseBeanTest;
20 | import info.novatec.beantest.demo.entities.MyEntityWithConstraints;
21 | import javax.persistence.PersistenceException;
22 | import static org.junit.Assert.fail;
23 | import org.junit.Test;
24 |
25 | /**
26 | * This test verifies that persistence exceptions are correctly propagated.
27 | *
28 | * @author Carlos Barragan (carlos.barragan@novatec-gmbh.de)
29 | */
30 | public class TestPersistenceExceptionPropagation extends BaseBeanTest {
31 |
32 |
33 |
34 | @Test(expected = PersistenceException.class)
35 | public void shouldCauseExceptionBecuaseUniquenessViolation() {
36 | MyEJBService myEJBService = getBean(MyEJBService.class);
37 | MyEntityWithConstraints entity=new MyEntityWithConstraints("123");
38 | myEJBService.save(entity);
39 | entity=new MyEntityWithConstraints("123");
40 | myEJBService.save(entity);
41 | fail("Should have failed because uniqueness violation");
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/test/java/info/novatec/beantest/demo/entities/MyEntity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Bean Testing.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package info.novatec.beantest.demo.entities;
17 |
18 | import java.io.Serializable;
19 | import javax.persistence.Entity;
20 | import javax.persistence.GeneratedValue;
21 | import javax.persistence.Id;
22 |
23 | /**
24 | * Demo Entity.
25 | *
26 | * @author Carlos Barragan (carlos.barragan@novatec-gmbh.de)
27 | */
28 | @Entity
29 | public class MyEntity implements Serializable {
30 |
31 | @GeneratedValue
32 | @Id
33 | private long id;
34 |
35 | private String name;
36 |
37 | private String anotherAttribute;
38 |
39 | public long getId() {
40 | return id;
41 | }
42 |
43 | public void setId(long id) {
44 | this.id = id;
45 | }
46 |
47 | public String getName() {
48 | return name;
49 | }
50 |
51 | public void setName(String name) {
52 | this.name = name;
53 | }
54 |
55 | public String getAnotherAttribute() {
56 | return anotherAttribute;
57 | }
58 |
59 | public void setAnotherAttribute(String anotherAttribute) {
60 | this.anotherAttribute = anotherAttribute;
61 | }
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/src/test/java/info/novatec/beantest/demo/ejb/TestExternalServices.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Bean Testing.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package info.novatec.beantest.demo.ejb;
18 |
19 | import info.novatec.beantest.api.BaseBeanTest;
20 | import info.novatec.beantest.demo.mocks.ExternalServicesMockProducer;
21 | import static org.hamcrest.CoreMatchers.is;
22 | import static org.junit.Assert.assertThat;
23 | import org.junit.Test;
24 | import org.mockito.Mockito;
25 |
26 | /**
27 | * This is an example to demonstrate how to test external services.
28 | *
29 | * @author Carlos Barragan (carlos.barragan@novatec-gmbh.de)
30 | */
31 | public class TestExternalServices extends BaseBeanTest {
32 |
33 |
34 | @Test
35 | public void shouldCallExternalServiceMock() {
36 | MyExternalService externalService= ExternalServicesMockProducer.getExternalService();
37 | //Since the ExternalServicesMockProducer returns a Mockito mock, we can initialize it
38 | Mockito.when(externalService.doSomething()).thenReturn("Hello World");
39 |
40 | MyEjbServiceThatCallsAnExternalService service= getBean(MyEjbServiceThatCallsAnExternalService.class);
41 | assertThat(service.callExternalService(), is("Hello World"));
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/main/java/info/novatec/beantest/extension/AnnotationInstances.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Bean Testing.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package info.novatec.beantest.extension;
17 |
18 | import info.novatec.beantest.transactions.Transactional;
19 | import javax.ejb.Singleton;
20 | import javax.enterprise.context.ApplicationScoped;
21 | import javax.enterprise.context.RequestScoped;
22 | import javax.inject.Inject;
23 | import org.apache.deltaspike.core.util.metadata.AnnotationInstanceProvider;
24 |
25 | /**
26 | * Class that contains constants of annotation instances.
27 | *
28 | * @author Carlos Barragan (carlos.barragan@novatec-gmbh.de)
29 | */
30 | public final class AnnotationInstances {
31 |
32 | private AnnotationInstances() {
33 |
34 | }
35 |
36 | public static final Transactional TRANSACTIONAL = AnnotationInstanceProvider.of(Transactional.class);
37 | public static final RequestScoped REQUEST_SCOPED = AnnotationInstanceProvider.of(RequestScoped.class);
38 | public static final Inject INJECT = AnnotationInstanceProvider.of(Inject.class);
39 | public static final Singleton SINGLETON = AnnotationInstanceProvider.of(Singleton.class);
40 | public static final ApplicationScoped APPLICATION_SCOPED = AnnotationInstanceProvider.of(ApplicationScoped.class);
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/src/test/java/info/novatec/beantest/demo/entities/MyEntityWithConstraints.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Bean Testing.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package info.novatec.beantest.demo.entities;
18 |
19 | import java.io.Serializable;
20 | import javax.persistence.Column;
21 | import javax.persistence.Entity;
22 | import javax.persistence.GeneratedValue;
23 | import javax.persistence.Id;
24 |
25 | /**
26 | * Demo entity that contains database constraints.
27 | *
28 | * @author Carlos Barragan (carlos.barragan@novatec-gmbh.de)
29 | */
30 | @Entity
31 | public class MyEntityWithConstraints implements Serializable{
32 |
33 | @Id
34 | @GeneratedValue
35 | private long id;
36 |
37 | @Column(unique = true)
38 | private String uniqueValue;
39 |
40 | /**
41 | * Constructor for JPA
42 | */
43 | protected MyEntityWithConstraints() {}
44 |
45 | public MyEntityWithConstraints(String uniqueValue) {
46 | this.uniqueValue = uniqueValue;
47 | }
48 |
49 | public String getUniqueValue() {
50 | return uniqueValue;
51 | }
52 |
53 | public void setUniqueValue(String uniqueValue) {
54 | this.uniqueValue = uniqueValue;
55 | }
56 |
57 | public long getId() {
58 | return id;
59 | }
60 |
61 |
62 |
63 |
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/src/test/java/info/novatec/beantest/demo/ejb/MyOtherEJBService.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Bean Testing.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package info.novatec.beantest.demo.ejb;
17 |
18 | import info.novatec.beantest.demo.entities.MyEntity;
19 | import info.novatec.beantest.demo.entities.MyEntityWithConstraints;
20 | import info.novatec.beantest.demo.exceptions.MyException;
21 | import java.util.Collection;
22 | import javax.ejb.Stateless;
23 | import javax.persistence.EntityManager;
24 | import javax.persistence.PersistenceContext;
25 | import org.slf4j.Logger;
26 | import org.slf4j.LoggerFactory;
27 |
28 | /**
29 | * Demo EJB Service.
30 | *
31 | * @author Carlos Barragan (carlos.barragan@novatec-gmbh.de)
32 | */
33 | @Stateless
34 | public class MyOtherEJBService {
35 | private static final Logger LOGGER=LoggerFactory.getLogger(MyOtherEJBService.class);
36 |
37 | @PersistenceContext(unitName = "db2")
38 | EntityManager entityManager;
39 |
40 | /**
41 | * It just logs a message.
42 | */
43 | public void doSomething() {
44 | LOGGER.info("MyOtherEJBService did something");
45 | }
46 |
47 | public Collection getAllEntities() {
48 | return entityManager.createQuery("Select E from MyEntity as E", MyEntity.class).getResultList();
49 | }
50 |
51 | /**
52 | * Throws MyException when called.
53 | *
54 | * See the corresponding test to better understand its purpose.
55 | */
56 | public void throwException() {
57 | throw new MyException("Oops, exception was thrown");
58 | }
59 |
60 | public void save(MyEntityWithConstraints entity) {
61 | entityManager.persist(entity);
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/test/java/info/novatec/beantest/demo/ejb/TestNoRollbackException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Bean Testing.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package info.novatec.beantest.demo.ejb;
18 |
19 | import info.novatec.beantest.api.BaseBeanTest;
20 | import info.novatec.beantest.demo.entities.MyEntity;
21 | import javax.persistence.NoResultException;
22 | import static org.hamcrest.Matchers.hasSize;
23 | import static org.hamcrest.Matchers.not;
24 | import static org.hamcrest.Matchers.nullValue;
25 | import static org.junit.Assert.assertThat;
26 | import static org.junit.Assert.fail;
27 | import org.junit.Test;
28 |
29 | /**
30 | * Tests that the exceptions documented in http://docs.oracle.com/javaee/6/api/javax/persistence/PersistenceException.html don't cause a rollback.
31 | *
32 | * @author Carlos Barragan (carlos.barragan@novatec-gmbh.de)
33 | */
34 | public class TestNoRollbackException extends BaseBeanTest {
35 |
36 | @Test
37 | public void shouldExceptionNoCauseRollback() {
38 | MyEJBService myEJBService = getBean(MyEJBService.class);
39 | MyOtherEJBService myOtherEJBService = getBean(MyOtherEJBService.class);
40 |
41 | assertThat(myOtherEJBService.getAllEntities(), hasSize(0));
42 |
43 | MyEntity entity = new MyEntity();
44 | entity.setName("some name");
45 | try {
46 | myEJBService.saveEntityAndCausePersistenceExceptionWithoutRollback(entity);
47 | fail("Should have thrown PersistenceException");
48 | } catch (NoResultException exception) {
49 | assertThat(exception, not(nullValue()));
50 | }
51 |
52 |
53 | //Entity should have been saved
54 | assertThat(myOtherEJBService.getAllEntities(), hasSize(1));
55 |
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/test/java/info/novatec/beantest/demo/ejb/DeltaSpikeEjbJpaTest.java:
--------------------------------------------------------------------------------
1 | package info.novatec.beantest.demo.ejb;
2 |
3 | import info.novatec.beantest.demo.entities.MyEntity;
4 | import info.novatec.beantest.demo.exceptions.MyException;
5 | import org.apache.deltaspike.testcontrol.api.junit.CdiTestRunner;
6 | import org.junit.Test;
7 | import org.junit.runner.RunWith;
8 |
9 | import javax.inject.Inject;
10 |
11 | import static org.hamcrest.Matchers.*;
12 | import static org.junit.Assert.*;
13 |
14 | /**
15 | * Rewrote adjacent tests from TestEJBInjection with DeltaSpike´s "test control" module in order to compare the
16 | * configurations needs, code style and importantly to check if the module provides an already solution for deploying
17 | * the concepts and ideas of CDI BeanTest.
18 | */
19 | @RunWith(CdiTestRunner.class)
20 | public class DeltaSpikeEjbJpaTest {
21 |
22 | @Inject
23 | private MyEJBService myService;
24 | @Inject
25 | private MyEJBServiceWithEntityManagerSetter myEJBServiceWithEntityManagerSetter;
26 |
27 | @Test
28 | public void shouldInjectEJBAsCDIBean() {
29 | myService.callOtherServiceAndPersistAnEntity();
30 | assertThat(myService.getOtherService2().getAllEntities(), hasSize(1));
31 | }
32 |
33 | @Test
34 | public void shouldPersistEntityInSpiteOfException() {
35 | MyEntity myEntity = new MyEntity();
36 | myEntity.setName("Foo");
37 | //An exception is thrown within the following method call, but because it is caught, the entity should have benn saved.
38 | myService.saveEntityAndHandleException(myEntity);
39 |
40 | assertThat(myService.getOtherService2().getAllEntities(), hasSize(1));
41 |
42 | }
43 |
44 | /**
45 | * Verifies that the transaction is rolled back properly when an Exception is thrown and not handled.
46 | */
47 | @Test
48 | public void shouldNotPersistEntityBecauseOfException() {
49 | MyEntity myEntity = new MyEntity();
50 | myEntity.setName("Foo");
51 | try {
52 | myService.attemptToSaveEntityAndThrowException(myEntity);
53 | fail("Should have thrown an exception");
54 | } catch (MyException e) {
55 | assertThat(myService.getOtherService2().getAllEntities(), is(empty()));
56 | }
57 | }
58 |
59 | @Test
60 | public void shouldInjectEJBAsCDIBeanUsingSetter() {
61 | assertNotNull(myService.getOtherService2());
62 | }
63 |
64 | @Test
65 | public void shouldInjectPersistenceContextUsingSetter() {
66 | assertNotNull(myEJBServiceWithEntityManagerSetter.getEm());
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/main/java/info/novatec/beantest/api/BeanProviderHelper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Bean Testing.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package info.novatec.beantest.api;
17 |
18 | import java.lang.annotation.Annotation;
19 | import javax.enterprise.inject.spi.BeanManager;
20 | import org.apache.deltaspike.cdise.api.CdiContainer;
21 | import org.apache.deltaspike.cdise.api.CdiContainerLoader;
22 | import org.apache.deltaspike.core.api.provider.BeanProvider;
23 |
24 | /**
25 | * Entry point to obtain bean references.
26 | *
27 | * @author Carlos Barragan (carlos.barragan@novatec-gmbh.de)
28 | */
29 | public class BeanProviderHelper {
30 |
31 | private CdiContainer cdiContainer;
32 | private static final BeanProviderHelper INSTANCE= new BeanProviderHelper();
33 |
34 | public static BeanProviderHelper getInstance() {
35 | return INSTANCE;
36 | }
37 |
38 | private BeanProviderHelper() {
39 | }
40 |
41 | /**
42 | * Starts the CDI Container and initializes its contexts.
43 | */
44 | private void bootstrapCdiContainer() {
45 | cdiContainer = CdiContainerLoader.getCdiContainer();
46 | cdiContainer.boot();
47 | cdiContainer.getContextControl().startContexts();
48 |
49 | }
50 |
51 |
52 | /**
53 | * Returns a reference of the given bean class.
54 | *
55 | * @param
56 | * the type of the bean.
57 | * @param beanClass
58 | * the class of the bean whose reference should be returned.
59 | * @param qualifiers
60 | * qualifiers for narrowing the bean instance. This attribute is not required.
61 | * @return the reference of the given bean class.
62 | */
63 | public T getBean(Class beanClass, Annotation... qualifiers) {
64 | if (cdiContainer == null) {
65 | bootstrapCdiContainer();
66 | }
67 | return BeanProvider.getContextualReference(beanClass, qualifiers);
68 | }
69 |
70 | /**
71 | * Returns the reference of the {@link BeanManager}.
72 | *
73 | * @return the reference of the {@link BeanManager}.
74 | */
75 | public BeanManager getBeanManager() {
76 | if (cdiContainer == null) {
77 | bootstrapCdiContainer();
78 | }
79 |
80 | return cdiContainer.getBeanManager();
81 | }
82 |
83 | /**
84 | * Shuts down the underlying container.
85 | */
86 | public void shutdown() {
87 | if (cdiContainer != null) {
88 | try {
89 | fireShutdownEvent();
90 | } finally {
91 | cdiContainer.shutdown();
92 | cdiContainer = null;
93 | }
94 |
95 | }
96 | }
97 |
98 | /**
99 | * Fires a {@link ContainerShutdown} CDI event before the CDI container shuts down in order to clean up resources (for example an
100 | * EntityManager).
101 | */
102 | private void fireShutdownEvent() {
103 | CdiContainerShutdown containerShutdown = new CdiContainerShutdown();
104 | getBeanManager().fireEvent(containerShutdown);
105 | }
106 |
107 |
108 | }
109 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://travis-ci.org/NovaTecConsulting/BeanTest)
2 |
3 | # Bean Testing for Java EE Applications using CDI
4 |
5 | This project attempts to show an interesting approach on testing Java EE
6 | Applications. It uses a CDI Container to resolve dependencies like EJBs
7 | or Resources when running unit test in a standard environment.
8 |
9 | The name "Bean Testing" is used, since it isn't about proper unit tests.
10 | However, the feedback speed is very close to unit test and the tests
11 | look undistinguishable too.
12 |
13 | **Main advantages:**
14 |
15 | - Very fast test feedback (very close to unit test feedback speed).
16 |
17 | - Dependencies are solved automatically without the need of a JEE
18 | Application Server (or Embedded Server).
19 |
20 | - Everything is CDI so you can easliy extend the functionality.
21 |
22 | - You get basic transaction propagation support.
23 |
24 | - You can provide your own mocks to test external dependencies.
25 |
26 | - You use the usual stuff for configuration: persistence.xml,
27 | beans.xml, Junit, etc.
28 |
29 | **Production ready**
30 |
31 | BeanTest is currently being used in some (big) customer projects. The projects are big Java EE Applications with several subsystems (.ear's). Each subsystem consists of several modules (.jar's) as well. We haven't faced any critical problem. Usually one can fix a problem by using standard CDI features.
32 |
33 | **Examples**
34 |
35 | You can find the examples about how a "Bean" test looks like under
36 | *src/test/java* (look for classes whose names begin with Test\*)
37 |
38 | ## How to use it
39 |
40 | * Add the following dependency in your pom:
41 |
42 | ```xml
43 |
44 |
45 | info.novatec
46 | bean-test
47 | {currentVersion}
48 | test
49 |
50 | ```
51 |
52 | * You also need to add the following repository to your pom:
53 |
54 | ```xml
55 |
56 | Novatec
57 | Novatec Repository
58 | http://repository.novatec-gmbh.de/content/repositories/novatec
59 |
60 | ```
61 | * Create an empty beans.xml file under src/test/resources/META-INF
62 |
63 | * Create a persistence unit called "beanTestPU" in your
64 | persistence.xml (you can place it under src/test/resources/META-INF)
65 |
66 | * Write a test similar to the ones in the examples using your
67 | production code.
68 |
69 | * Depending on your project structure, you might get an
70 | *UnsatisfiedResolutionException* if some classes are not available
71 | in your classpath. You can solve this by providing a Mock (See the
72 | mock example for this).
73 |
74 | ## Why you should use it
75 |
76 | First of all, this approach is neither a replacement for unit nor
77 | integration tests. This approach is something in the middle.
78 |
79 | You should always write unit tests for essential business logic.
80 |
81 | You should always write integration tests to check that everything works
82 | as expected.
83 |
84 | So, why use this approach? Because you get the best of both worlds: You
85 | get the speed of unit tests with almost the coverage of integration
86 | tests and all this with minimal configuration and with standard and well
87 | known frameworks like JPA, CDI, Mockito and Junit.
88 |
89 | Since you don't need an application server for running your tests, you
90 | can integrate them in your normal unit test build process. In this way,
91 | you get almost integration test coverage in your normal builds.
92 |
93 | ### Requirements
94 |
95 | - JDK 6 and above.
96 |
97 | - Maven
98 |
99 | ### Contribute
100 |
101 | Just fork.
102 |
--------------------------------------------------------------------------------
/src/test/java/info/novatec/beantest/demo/ejb/TestEJBInjection.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Bean Testing.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package info.novatec.beantest.demo.ejb;
17 |
18 | import static org.hamcrest.Matchers.empty;
19 | import static org.hamcrest.Matchers.hasSize;
20 | import static org.hamcrest.Matchers.is;
21 | import static org.junit.Assert.assertNotNull;
22 | import static org.junit.Assert.assertThat;
23 | import static org.junit.Assert.fail;
24 | import info.novatec.beantest.api.BaseBeanTest;
25 | import info.novatec.beantest.demo.entities.MyEntity;
26 | import info.novatec.beantest.demo.exceptions.MyException;
27 |
28 | import org.junit.Test;
29 |
30 | /**
31 | * This test verifies that all dependencies are properly resolved as well as the
32 | * transaction is properly propagated among calls.
33 | *
34 | * The database schema is recreated for every test method.
35 | *
36 | * @author Carlos Barragan (carlos.barragan@novatec-gmbh.de)
37 | */
38 | public class TestEJBInjection extends BaseBeanTest {
39 |
40 | @Test
41 | public void shouldInjectEJBAsCDIBean() {
42 | MyEJBService myService = getBean(MyEJBService.class);
43 | //An Entity should be persisted and you should see a message logged in the console.
44 | myService.callOtherServiceAndPersistAnEntity();
45 | //Let's create a reference of another EJB to query the database.
46 | MyOtherEJBService myOtherService = getBean(MyOtherEJBService.class);
47 |
48 | assertThat(myOtherService.getAllEntities(), hasSize(1));
49 |
50 | }
51 |
52 | /**
53 | * Verifies that an entity is saved when an exception is caught by its caller.
54 | */
55 | @Test
56 | public void shouldPersistEntityInSpiteOfException() {
57 | MyEJBService myService = getBean(MyEJBService.class);
58 | MyEntity myEntity=new MyEntity();
59 | myEntity.setName("Foo");
60 | //An exception is thrown within the following method call, but because it is caught, the entity should have benn saved.
61 | myService.saveEntityAndHandleException(myEntity);
62 |
63 | MyOtherEJBService myOtherService = getBean(MyOtherEJBService.class);
64 | assertThat(myOtherService.getAllEntities(), hasSize(1));
65 |
66 | }
67 |
68 | /**
69 | * Verifies that the transaction is rolled back properly when an Exception is thrown and not handled.
70 | */
71 | @Test
72 | public void shouldNotPersistEntityBecauseOfException() {
73 | MyEJBService myService = getBean(MyEJBService.class);
74 | MyEntity myEntity=new MyEntity();
75 | myEntity.setName("Foo");
76 | try {
77 | myService.attemptToSaveEntityAndThrowException(myEntity);
78 | fail("Should have thrown an exception");
79 | } catch(MyException e) {
80 | MyOtherEJBService myOtherService = getBean(MyOtherEJBService.class);
81 | assertThat(myOtherService.getAllEntities(), is(empty()));
82 | }
83 |
84 |
85 |
86 | }
87 |
88 | @Test
89 | public void shouldInjectEJBAsCDIBeanUsingSetter() {
90 | MyEJBService myService = getBean(MyEJBService.class);
91 |
92 | assertNotNull(myService.getOtherService2());
93 | }
94 |
95 | @Test
96 | public void shouldInjectPersistenceContextUsingSetter() {
97 | MyEJBServiceWithEntityManagerSetter myService = getBean(MyEJBServiceWithEntityManagerSetter.class);
98 |
99 | assertNotNull(myService.getEm());
100 | }
101 |
102 | }
103 |
--------------------------------------------------------------------------------
/src/test/java/info/novatec/beantest/demo/ejb/MyEJBService.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Bean Testing.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package info.novatec.beantest.demo.ejb;
17 |
18 | import info.novatec.beantest.demo.entities.MyEntity;
19 | import info.novatec.beantest.demo.entities.MyEntityWithConstraints;
20 | import info.novatec.beantest.demo.exceptions.MyException;
21 | import javax.ejb.EJB;
22 | import javax.ejb.Stateless;
23 | import javax.persistence.EntityManager;
24 | import javax.persistence.PersistenceContext;
25 | import javax.persistence.PersistenceException;
26 | import org.slf4j.Logger;
27 | import org.slf4j.LoggerFactory;
28 |
29 | /**
30 | * Demo EJB Service.
31 | *
32 | * This EJB serves as a facade. It calls {@link MyOtherEJBService} to simulate transaction propagation. Furthermore, it provides
33 | * some methods to test proper transaction handling when exceptions are thrown.
34 | *
35 | * @author Carlos Barragan (carlos.barragan@novatec-gmbh.de)
36 | */
37 | @Stateless
38 | public class MyEJBService {
39 |
40 | private static final Logger LOGGER=LoggerFactory.getLogger(MyEJBService.class);
41 |
42 | @EJB
43 | MyOtherEJBService otherService;
44 |
45 | MyOtherEJBService otherService2;
46 |
47 | @PersistenceContext(unitName = "db2")
48 | EntityManager em;
49 |
50 | @EJB
51 | public void setOtherService2(MyOtherEJBService otherService2) {
52 | this.otherService2 = otherService2;
53 | }
54 |
55 | public MyOtherEJBService getOtherService2() {
56 | return otherService2;
57 | }
58 |
59 | /**
60 | * This method calls {@link MyOtherEJBService#doSomething() } and saves a new {@link MyEntity}.
61 | */
62 | public void callOtherServiceAndPersistAnEntity() {
63 | otherService.doSomething();
64 | MyEntity entity = new MyEntity();
65 | entity.setName("Hello");
66 | em.persist(entity);
67 | LOGGER.info("Entity persisted!");
68 | }
69 |
70 | /**
71 | * Saves the given entity even though an exception is thrown when calling {@link MyOtherEJBService#throwException()}.
72 | *
73 | * @param entity the entity that should be saved.
74 | */
75 | public void saveEntityAndHandleException(MyEntity entity) {
76 | try {
77 | em.persist(entity);
78 | otherService.throwException();
79 | } catch(MyException e) {
80 | //Empty on purpose. Entity was persisted in spite of the exception.
81 | }
82 | }
83 |
84 | /**
85 | * Tries to persist the given entity but an exception is thrown instead because {@link MyOtherEJBService#throwException()} is called.
86 | *
87 | * @param entity the entity that should be saved.
88 | */
89 | public void attemptToSaveEntityAndThrowException(MyEntity entity) {
90 | em.persist(entity);
91 | otherService.throwException();
92 | //Entity should have not been persisted.
93 | }
94 |
95 | /**
96 | * Persists the given entity and throws a {@link PersistenceException} that should not rollback the transaction
97 | *
98 | * @param entity the entity that should be persisted
99 | *
100 | * @see http://docs.oracle.com/javaee/6/api/javax/persistence/PersistenceException.html
101 | */
102 | public void saveEntityAndCausePersistenceExceptionWithoutRollback(MyEntity entity) {
103 | em.persist(entity);
104 | //Throw a NoResultFoundException.
105 | em.createQuery("Select e from MyEntity as e where e.id = :nonExistentId").setParameter("nonExistentId", -42L).getSingleResult();
106 | }
107 |
108 | /**
109 | * Saves the given entity by delegating the call to {@link MyOtherEJBService#save(info.novatec.beantest.demo.entities.MyEntityWithConstraints)}
110 | * @param entity the entity that should be saved.
111 | */
112 | public void save(MyEntityWithConstraints entity) {
113 | otherService.save(entity);
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/src/main/java/info/novatec/beantest/producers/EntityManagerProducer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Bean Testing.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package info.novatec.beantest.producers;
17 |
18 | import info.novatec.beantest.api.CdiContainerShutdown;
19 | import java.lang.reflect.Member;
20 | import java.lang.reflect.Method;
21 | import javax.annotation.PostConstruct;
22 | import javax.enterprise.context.RequestScoped;
23 | import javax.enterprise.event.Observes;
24 | import javax.enterprise.inject.Produces;
25 | import javax.enterprise.inject.spi.InjectionPoint;
26 | import javax.persistence.EntityManager;
27 | import javax.persistence.EntityManagerFactory;
28 | import javax.persistence.Persistence;
29 | import javax.persistence.PersistenceContext;
30 | import org.slf4j.Logger;
31 | import org.slf4j.LoggerFactory;
32 |
33 | /**
34 | * Entity manager producer.
35 | *
36 | * It initializes the entity manager to be injected in EJBs
37 | *
38 | * @author Carlos Barragan (carlos.barragan@novatec-gmbh.de)
39 | */
40 | @RequestScoped
41 | public class EntityManagerProducer {
42 |
43 | private static final Logger LOGGER = LoggerFactory.getLogger(EntityManagerProducer.class);
44 |
45 | private static final String DEFAULT_BEAN_TEST_PERSISTENCE_UNIT = "beanTestPU";
46 |
47 | private EntityManagerFactory emf;
48 |
49 | private EntityManager em;
50 |
51 | @PostConstruct
52 | private void initializeEntityManagerFactory() {
53 | emf = Persistence.createEntityManagerFactory(DEFAULT_BEAN_TEST_PERSISTENCE_UNIT);
54 | LOGGER.info("Entity Manager Factory was successfully initialized");
55 |
56 | }
57 |
58 |
59 | @Produces
60 | public EntityManager getEntityManager(InjectionPoint ip) {
61 | PersistenceContext ctx = ip.getAnnotated().getAnnotation(PersistenceContext.class);
62 |
63 | if (ctx == null) {
64 | //if @PersisteceContext is declared on method, ctx is null at this point.
65 | //ctx should be retrieved from the Method.
66 | Member member = ip.getMember();
67 | if (member instanceof Method) {
68 | Method method = (Method) member;
69 | ctx = method.getAnnotation(PersistenceContext.class);
70 | }
71 | }
72 |
73 | LOGGER.debug("PersistenceContext info:");
74 | //This could happen if the application injects the EntityManager via @Inject instead of @PersistenceContext
75 | if(ctx != null) {
76 | LOGGER.debug("Unit name: {}", ctx.unitName());
77 | }
78 |
79 | LOGGER.debug("Bean defining the injection point: {}", ip.getBean().getBeanClass());
80 | LOGGER.debug("Field to be injected: {}", ip.getMember());
81 |
82 | if (em == null) {
83 | em = emf.createEntityManager();
84 | }
85 | return em;
86 | }
87 |
88 | /**
89 | * Closes the entity manager and entity manager factory when the event {@link CdiContainerShutdown} is fired.
90 | *
91 | * @param containerShutdown
92 | * the event that indicates that the container is about to shutdown.
93 | */
94 | public void closeEntityManagerAndEntityManagerFactory(@Observes CdiContainerShutdown containerShutdown) {
95 | closeEntityManager();
96 | closeEntityManagerFactory();
97 | }
98 |
99 | private void closeEntityManager() {
100 | if (em == null) {
101 | return;
102 | }
103 | if (em.isOpen()) {
104 | try {
105 | // In case a transaction is still open.
106 | if (em.getTransaction().isActive() && !em.getTransaction().getRollbackOnly()) {
107 | em.getTransaction().commit();
108 | }
109 | } finally {
110 | LOGGER.debug("Closing entity manager");
111 | em.close();
112 | }
113 |
114 | }
115 | }
116 |
117 | private void closeEntityManagerFactory() {
118 | if (emf == null) {
119 | return;
120 | }
121 | if (emf.isOpen()) {
122 | LOGGER.debug("Closing entity manager factory");
123 | emf.close();
124 | }
125 | }
126 |
127 | }
128 |
--------------------------------------------------------------------------------
/src/main/java/info/novatec/beantest/extension/InjectionHelper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Bean Testing.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package info.novatec.beantest.extension;
17 |
18 | import java.lang.annotation.Annotation;
19 | import java.util.Collections;
20 | import java.util.HashSet;
21 | import java.util.Set;
22 | import javax.annotation.Resource;
23 | import javax.ejb.EJB;
24 | import javax.enterprise.inject.spi.AnnotatedField;
25 | import javax.enterprise.inject.spi.AnnotatedMember;
26 | import javax.enterprise.inject.spi.AnnotatedMethod;
27 | import javax.enterprise.inject.spi.AnnotatedType;
28 | import javax.inject.Inject;
29 | import javax.persistence.PersistenceContext;
30 | import org.apache.deltaspike.core.util.metadata.builder.AnnotatedTypeBuilder;
31 |
32 | /**
33 | * This class provides general convenience methods for injection and validation.
34 | *
35 | * @author Carlos Barragan (carlos.barragan@novatec-gmbh.de)
36 | */
37 | public final class InjectionHelper {
38 |
39 | private static final Set> JAVA_EE_ANNOTATIONS = createJavaEEAnnotationSet();
40 |
41 | private static Set> createJavaEEAnnotationSet() {
42 | Set> javaEEAnnotations = new HashSet>();
43 | javaEEAnnotations.add(Resource.class);
44 | javaEEAnnotations.add(EJB.class);
45 | javaEEAnnotations.add(PersistenceContext.class);
46 | return Collections.unmodifiableSet(javaEEAnnotations);
47 | }
48 |
49 | private InjectionHelper() {
50 | // Empty on purpose.
51 | }
52 |
53 | /**
54 | * Returns true if the member is NOT annotated with {@link Inject} and is annotated with one of the following annotations:
55 | *
56 | *
{@link EJB}
57 | *
{@link PersistenceContext}
58 | *
{@link Resource}
59 | *
60 | * Otherwise, it returns false.
61 | *
62 | * @param
63 | * the type of the annotated member
64 | * @param member
65 | * the annotated member whose annotations should be verified.
66 | * @return true if the member is NOT annotated with {@link Inject} and is annotated with {@link EJB},
67 | * {@link PersistenceContext} or {@link Resource}
68 | */
69 | public static boolean shouldInjectionAnnotationBeAddedToMember(AnnotatedMember super X> member) {
70 | return !member.isAnnotationPresent(Inject.class) && hasJavaEEAnnotations(member);
71 | }
72 |
73 | /**
74 | * Returns true if at least one of the following Java EE annotations is present in the given member:
75 | *
76 | *
{@link EJB}
77 | *
{@link PersistenceContext}
78 | *
{@link Resource}
79 | *
80 | * Otherwise, it returns false.
81 | * @param the type of the annotated member.
82 | * @param member the member whose annotations should be verified.
83 | * @return true if the member is at least annotated with one of the following annotations: {@link EJB}, {@link PersistenceContext} or {@link Resource}.
84 | */
85 | private static boolean hasJavaEEAnnotations(AnnotatedMember super X> member) {
86 | for(Class extends Annotation> javaEEannotation : JAVA_EE_ANNOTATIONS) {
87 | if (member.isAnnotationPresent(javaEEannotation)) {
88 | return true;
89 | }
90 | }
91 | return false;
92 | }
93 |
94 | /**
95 | * Adds the {@link Inject} annotation to the fields and setters of the annotated type if required.
96 | *
97 | * @param
98 | * the type of the annotated type
99 | * @param annotatedType
100 | * the annotated type whose fields and setters the inject annotation should be added to
101 | * @param builder
102 | * the builder that should be used to add the annotation.
103 | * @see #shouldInjectionAnnotationBeAddedToMember(AnnotatedMember)
104 | */
105 | public static void addInjectAnnotation(final AnnotatedType annotatedType, AnnotatedTypeBuilder builder) {
106 | for (AnnotatedField super X> field : annotatedType.getFields()) {
107 | if (shouldInjectionAnnotationBeAddedToMember(field)) {
108 | builder.addToField(field, AnnotationInstances.INJECT);
109 | }
110 | }
111 | for (AnnotatedMethod super X> method : annotatedType.getMethods()) {
112 | if (shouldInjectionAnnotationBeAddedToMember(method)) {
113 | builder.addToMethod(method, AnnotationInstances.INJECT);
114 | }
115 | }
116 | }
117 |
118 |
119 | }
120 |
--------------------------------------------------------------------------------
/src/main/java/info/novatec/beantest/extension/BeanTestExtension.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Bean Testing.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package info.novatec.beantest.extension;
17 |
18 | import info.novatec.beantest.transactions.Transactional;
19 | import javax.ejb.EJB;
20 | import javax.ejb.MessageDriven;
21 | import javax.ejb.Singleton;
22 | import javax.ejb.Stateless;
23 | import javax.enterprise.context.ApplicationScoped;
24 | import javax.enterprise.context.RequestScoped;
25 | import javax.enterprise.event.Observes;
26 | import javax.enterprise.inject.spi.AnnotatedType;
27 | import javax.enterprise.inject.spi.Extension;
28 | import javax.enterprise.inject.spi.ProcessAnnotatedType;
29 | import javax.enterprise.inject.spi.WithAnnotations;
30 | import javax.inject.Inject;
31 | import javax.interceptor.Interceptor;
32 | import org.apache.deltaspike.core.util.metadata.builder.AnnotatedTypeBuilder;
33 |
34 | /**
35 | * Extension to modify bean meta data.
36 | *
37 | * This extension adds and changes the bean meta data in order to convert EJB injection points into CDI injection points.
38 | * Therefore the extension changes the meta data of Beans annotated with {@link EJB}
39 | * It also changes injection points in interceptors.
40 | *
41 | * @author Carlos Barragan (carlos.barragan@novatec-gmbh.de)
42 | */
43 | public class BeanTestExtension implements Extension {
44 |
45 |
46 |
47 | /**
48 | * Replaces the meta data of the {@link ProcessAnnotatedType}.
49 | *
50 | *
51 | * The ProcessAnnotatedType's meta data will be replaced, if the annotated type has one of the following annotations:
52 | *
53 | *
{@link Stateless}
54 | *
{@link MessageDriven}
55 | *
{@link Interceptor}
56 | *
{@link Singleton}
57 | *
58 | *
59 | * @param the type of the ProcessAnnotatedType
60 | * @param pat the annotated type representing the class being processed
61 | */
62 | public void processInjectionTarget(@Observes @WithAnnotations({Stateless.class, MessageDriven.class, Interceptor.class, Singleton.class}) ProcessAnnotatedType pat) {
63 | if (pat.getAnnotatedType().isAnnotationPresent(Stateless.class) || pat.getAnnotatedType().isAnnotationPresent(MessageDriven.class)) {
64 | modifiyAnnotatedTypeMetadata(pat);
65 | } else if (pat.getAnnotatedType().isAnnotationPresent(Interceptor.class)) {
66 | processInterceptorDependencies(pat);
67 | } else if(pat.getAnnotatedType().isAnnotationPresent(Singleton.class)) {
68 | addApplicationScopedAndTransactionalToSingleton(pat);
69 | }
70 | }
71 |
72 | /**
73 | * Adds {@link Transactional} and {@link ApplicationScoped} to the given annotated type and converts
74 | * its EJB injection points into CDI injection points (i.e. it adds the {@link Inject})
75 | * @param the type of the annotated type.
76 | * @param pat the process annotated type.
77 | */
78 | private void addApplicationScopedAndTransactionalToSingleton(ProcessAnnotatedType pat) {
79 | AnnotatedType at = pat.getAnnotatedType();
80 |
81 | AnnotatedTypeBuilder builder = new AnnotatedTypeBuilder().readFromType(at);
82 |
83 | builder.addToClass(AnnotationInstances.APPLICATION_SCOPED).addToClass(AnnotationInstances.TRANSACTIONAL);
84 |
85 | InjectionHelper.addInjectAnnotation(at, builder);
86 |
87 | pat.setAnnotatedType(builder.create());
88 | }
89 |
90 | /**
91 | * Adds {@link Transactional} and {@link RequestScoped} to the given annotated type and converts
92 | * its EJB injection points into CDI injection points (i.e. it adds the {@link Inject})
93 | * @param the type of the annotated type
94 | * @param pat the process annotated type.
95 | */
96 | private void modifiyAnnotatedTypeMetadata(ProcessAnnotatedType pat) {
97 | AnnotatedType at = pat.getAnnotatedType();
98 |
99 | AnnotatedTypeBuilder builder = new AnnotatedTypeBuilder().readFromType(at);
100 | builder.addToClass(AnnotationInstances.TRANSACTIONAL).addToClass(AnnotationInstances.REQUEST_SCOPED);
101 |
102 | InjectionHelper.addInjectAnnotation(at, builder);
103 | //Set the wrapper instead the actual annotated type
104 | pat.setAnnotatedType(builder.create());
105 |
106 | }
107 |
108 | /**
109 | * Adds {@link Inject} annotation to all the dependencies of the interceptor.
110 | *
111 | * @param
112 | * the type of the annotated type
113 | * @param pat
114 | * the process annotated type.
115 | */
116 | private void processInterceptorDependencies(ProcessAnnotatedType pat) {
117 | AnnotatedTypeBuilder builder = new AnnotatedTypeBuilder().readFromType(pat.getAnnotatedType());
118 | InjectionHelper.addInjectAnnotation(pat.getAnnotatedType(), builder);
119 | pat.setAnnotatedType(builder.create());
120 | }
121 |
122 |
123 | }
124 |
--------------------------------------------------------------------------------
/src/main/java/info/novatec/beantest/transactions/TransactionalInterceptor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Bean Testing.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package info.novatec.beantest.transactions;
17 |
18 | import java.util.Arrays;
19 | import java.util.HashSet;
20 | import java.util.Set;
21 | import javax.inject.Inject;
22 | import javax.interceptor.AroundInvoke;
23 | import javax.interceptor.Interceptor;
24 | import javax.interceptor.InvocationContext;
25 | import javax.persistence.EntityManager;
26 | import javax.persistence.EntityTransaction;
27 | import javax.persistence.LockTimeoutException;
28 | import javax.persistence.NoResultException;
29 | import javax.persistence.NonUniqueResultException;
30 | import javax.persistence.PersistenceContext;
31 | import javax.persistence.QueryTimeoutException;
32 | import org.slf4j.Logger;
33 | import org.slf4j.LoggerFactory;
34 |
35 | /**
36 | * Transactional interceptor to provide basic transaction propagation.
37 | *
38 | * Note This implementation is intentionally not thread-safe, because unit tests are usually run in one thread.
39 | * If you try to run unit tests in parallel, unexpected behavior may occur.
40 | *
41 | * Alternatively the Apache Deltaspike JPA module can be used. The JPA module provides more advanced transaction handling.
42 | * However, this implementation should suffice for testing purposes.
43 | *
44 | * @author Carlos Barragan (carlos.barragan@novatec-gmbh.de)
45 | */
46 | @Interceptor
47 | @Transactional
48 | public class TransactionalInterceptor {
49 |
50 | /**
51 | * Exceptions that should not cause the transaction to rollback according to Java EE Documentation.
52 | * (http://docs.oracle.com/javaee/6/api/javax/persistence/PersistenceException.html)
53 | */
54 | private static final Set> NO_ROLLBACK_EXCEPTIONS=new HashSet>(Arrays.asList(
55 | NonUniqueResultException.class,
56 | NoResultException.class,
57 | QueryTimeoutException.class,
58 | LockTimeoutException.class));
59 |
60 |
61 | @Inject
62 | @PersistenceContext
63 | EntityManager em;
64 |
65 | private static final Logger LOGGER = LoggerFactory.getLogger(TransactionalInterceptor.class);
66 |
67 | private static int INTERCEPTOR_COUNTER = 0;
68 |
69 | @AroundInvoke
70 | public Object manageTransaction(InvocationContext ctx) throws Exception {
71 |
72 | EntityTransaction transaction = em.getTransaction();
73 | if (!transaction.isActive()) {
74 | transaction.begin();
75 | LOGGER.debug("Transaction started");
76 | }
77 |
78 | INTERCEPTOR_COUNTER++;
79 | Object result = null;
80 | try {
81 | result = ctx.proceed();
82 |
83 | } catch (Exception e) {
84 | if (isFirstInterceptor()) {
85 | markRollbackTransaction(e);
86 | }
87 | throw e;
88 | } finally {
89 | processTransaction();
90 | }
91 |
92 | return result;
93 | }
94 |
95 |
96 |
97 | /**
98 | * Commits the current transaction if it is not already marked as rollback via the {@link EntityTransaction#getRollbackOnly()} method.
99 | * In that case, a rollback will be executed.
100 | */
101 | private void processTransaction() throws Exception {
102 | EntityTransaction transaction = em.getTransaction();
103 | try {
104 |
105 | if (em.isOpen() && transaction.isActive() && isFirstInterceptor()) {
106 | if (transaction.getRollbackOnly()) {
107 | transaction.rollback();
108 | LOGGER.debug("Transaction was rollbacked");
109 | } else {
110 | transaction.commit();
111 | LOGGER.debug("Transaction committed");
112 | }
113 | em.clear();
114 | }
115 | } catch (Exception e) {
116 | LOGGER.warn("Error when trying to commit transaction: {0}", e);
117 | throw e;
118 | } finally {
119 | INTERCEPTOR_COUNTER--;
120 | }
121 |
122 | }
123 |
124 | /**
125 | * Marks the transaction for rollback via {@link EntityTransaction#setRollbackOnly()}.
126 | */
127 | private void markRollbackTransaction(Exception exception) throws Exception {
128 | try {
129 | if (em.isOpen() && em.getTransaction().isActive() && shouldExceptionCauseRollback(exception)) {
130 | em.getTransaction().setRollbackOnly();
131 | }
132 | } catch (Exception e) {
133 | LOGGER.warn("Error when trying to roll back the transaction: {0}", e);
134 | throw e;
135 | }
136 |
137 | }
138 |
139 | private static boolean isFirstInterceptor() {
140 | return INTERCEPTOR_COUNTER -1 == 0;
141 | }
142 |
143 | private static boolean shouldExceptionCauseRollback(Exception e ) {
144 | return ! NO_ROLLBACK_EXCEPTIONS.contains(e.getClass());
145 | }
146 |
147 | }
148 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 | info.novatec
5 | bean-test
6 | 0.3-SNAPSHOT
7 | Bean Testing
8 | Java EE Bean Testing framework
9 | http://blog.novatec-gmbh.de/unit-testing-jee-applications-cdi/
10 | jar
11 |
12 |
13 | UTF-8
14 | 1.2.1
15 |
16 |
17 |
18 |
19 | org.slf4j
20 | slf4j-api
21 | 1.7.5
22 | jar
23 |
24 |
25 | org.hibernate
26 | hibernate-core
27 | 4.2.8.Final
28 | provided
29 |
30 |
31 | org.hibernate
32 | hibernate-entitymanager
33 | 4.2.8.Final
34 | provided
35 |
36 |
37 | org.apache.geronimo.specs
38 | geronimo-ejb_3.1_spec
39 | 1.0
40 |
41 |
42 | org.apache.geronimo.specs
43 | geronimo-jpa_2.0_spec
44 | 1.0
45 |
46 |
47 | org.jboss.weld.se
48 | weld-se
49 | 2.1.2.Final
50 | jar
51 |
52 |
53 |
54 | org.hamcrest
55 | hamcrest-all
56 | 1.3
57 | test
58 |
59 |
60 |
61 | junit
62 | junit
63 | 4.11
64 |
65 |
66 |
67 | org.apache.derby
68 | derby
69 | 10.10.1.1
70 | test
71 |
72 |
73 | org.apache.deltaspike.core
74 | deltaspike-core-impl
75 | ${deltaspike.version}
76 |
77 |
78 | org.apache.deltaspike.cdictrl
79 | deltaspike-cdictrl-weld
80 | ${deltaspike.version}
81 |
82 |
83 | org.apache.deltaspike.modules
84 | deltaspike-test-control-module-api
85 | ${deltaspike.version}
86 | test
87 |
88 |
89 | org.apache.deltaspike.modules
90 | deltaspike-test-control-module-impl
91 | ${deltaspike.version}
92 | test
93 |
94 |
95 | org.mockito
96 | mockito-all
97 | 1.8.4
98 | test
99 |
100 |
101 |
102 |
103 | https://github.com/NovaTecConsulting/BeanTest.git
104 |
105 |
106 |
107 |
108 |
109 |
110 | org.apache.maven.plugins
111 | maven-compiler-plugin
112 | 2.3.2
113 |
114 | 1.6
115 | 1.6
116 |
117 |
118 |
119 | org.apache.maven.plugins
120 | maven-source-plugin
121 | 2.2.1
122 |
123 |
124 | attach-sources
125 |
126 | jar
127 |
128 |
129 |
130 |
131 |
132 | org.apache.maven.plugins
133 | maven-javadoc-plugin
134 | 2.9.1
135 |
136 |
137 | attach-javadocs
138 |
139 | jar
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 | The Apache Software License, Version 2.0
150 | http://www.apache.org/licenses/LICENSE-2.0.txt
151 | manual
152 |
153 |
154 |
155 |
156 | github
157 | GitHub Packages
158 | https://maven.pkg.github.com/novatec-gmbh/bean-test
159 |
160 |
161 |
162 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction, and
10 | distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by the copyright
13 | owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all other entities
16 | that control, are controlled by, or are under common control with that entity.
17 | For the purposes of this definition, "control" means (i) the power, direct or
18 | indirect, to cause the direction or management of such entity, whether by
19 | contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
20 | outstanding shares, or (iii) beneficial ownership of such entity.
21 |
22 | "You" (or "Your") shall mean an individual or Legal Entity exercising
23 | permissions granted by this License.
24 |
25 | "Source" form shall mean the preferred form for making modifications, including
26 | but not limited to software source code, documentation source, and configuration
27 | files.
28 |
29 | "Object" form shall mean any form resulting from mechanical transformation or
30 | translation of a Source form, including but not limited to compiled object code,
31 | generated documentation, and conversions to other media types.
32 |
33 | "Work" shall mean the work of authorship, whether in Source or Object form, made
34 | available under the License, as indicated by a copyright notice that is included
35 | in or attached to the work (an example is provided in the Appendix below).
36 |
37 | "Derivative Works" shall mean any work, whether in Source or Object form, that
38 | is based on (or derived from) the Work and for which the editorial revisions,
39 | annotations, elaborations, or other modifications represent, as a whole, an
40 | original work of authorship. For the purposes of this License, Derivative Works
41 | shall not include works that remain separable from, or merely link (or bind by
42 | name) to the interfaces of, the Work and Derivative Works thereof.
43 |
44 | "Contribution" shall mean any work of authorship, including the original version
45 | of the Work and any modifications or additions to that Work or Derivative Works
46 | thereof, that is intentionally submitted to Licensor for inclusion in the Work
47 | by the copyright owner or by an individual or Legal Entity authorized to submit
48 | on behalf of the copyright owner. For the purposes of this definition,
49 | "submitted" means any form of electronic, verbal, or written communication sent
50 | to the Licensor or its representatives, including but not limited to
51 | communication on electronic mailing lists, source code control systems, and
52 | issue tracking systems that are managed by, or on behalf of, the Licensor for
53 | the purpose of discussing and improving the Work, but excluding communication
54 | that is conspicuously marked or otherwise designated in writing by the copyright
55 | owner as "Not a Contribution."
56 |
57 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf
58 | of whom a Contribution has been received by Licensor and subsequently
59 | incorporated within the Work.
60 |
61 | 2. Grant of Copyright License.
62 |
63 | Subject to the terms and conditions of this License, each Contributor hereby
64 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
65 | irrevocable copyright license to reproduce, prepare Derivative Works of,
66 | publicly display, publicly perform, sublicense, and distribute the Work and such
67 | Derivative Works in Source or Object form.
68 |
69 | 3. Grant of Patent License.
70 |
71 | Subject to the terms and conditions of this License, each Contributor hereby
72 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
73 | irrevocable (except as stated in this section) patent license to make, have
74 | made, use, offer to sell, sell, import, and otherwise transfer the Work, where
75 | such license applies only to those patent claims licensable by such Contributor
76 | that are necessarily infringed by their Contribution(s) alone or by combination
77 | of their Contribution(s) with the Work to which such Contribution(s) was
78 | submitted. If You institute patent litigation against any entity (including a
79 | cross-claim or counterclaim in a lawsuit) alleging that the Work or a
80 | Contribution incorporated within the Work constitutes direct or contributory
81 | patent infringement, then any patent licenses granted to You under this License
82 | for that Work shall terminate as of the date such litigation is filed.
83 |
84 | 4. Redistribution.
85 |
86 | You may reproduce and distribute copies of the Work or Derivative Works thereof
87 | in any medium, with or without modifications, and in Source or Object form,
88 | provided that You meet the following conditions:
89 |
90 | You must give any other recipients of the Work or Derivative Works a copy of
91 | this License; and
92 | You must cause any modified files to carry prominent notices stating that You
93 | changed the files; and
94 | You must retain, in the Source form of any Derivative Works that You distribute,
95 | all copyright, patent, trademark, and attribution notices from the Source form
96 | of the Work, excluding those notices that do not pertain to any part of the
97 | Derivative Works; and
98 | If the Work includes a "NOTICE" text file as part of its distribution, then any
99 | Derivative Works that You distribute must include a readable copy of the
100 | attribution notices contained within such NOTICE file, excluding those notices
101 | that do not pertain to any part of the Derivative Works, in at least one of the
102 | following places: within a NOTICE text file distributed as part of the
103 | Derivative Works; within the Source form or documentation, if provided along
104 | with the Derivative Works; or, within a display generated by the Derivative
105 | Works, if and wherever such third-party notices normally appear. The contents of
106 | the NOTICE file are for informational purposes only and do not modify the
107 | License. You may add Your own attribution notices within Derivative Works that
108 | You distribute, alongside or as an addendum to the NOTICE text from the Work,
109 | provided that such additional attribution notices cannot be construed as
110 | modifying the License.
111 | You may add Your own copyright statement to Your modifications and may provide
112 | additional or different license terms and conditions for use, reproduction, or
113 | distribution of Your modifications, or for any such Derivative Works as a whole,
114 | provided Your use, reproduction, and distribution of the Work otherwise complies
115 | with the conditions stated in this License.
116 |
117 | 5. Submission of Contributions.
118 |
119 | Unless You explicitly state otherwise, any Contribution intentionally submitted
120 | for inclusion in the Work by You to the Licensor shall be under the terms and
121 | conditions of this License, without any additional terms or conditions.
122 | Notwithstanding the above, nothing herein shall supersede or modify the terms of
123 | any separate license agreement you may have executed with Licensor regarding
124 | such Contributions.
125 |
126 | 6. Trademarks.
127 |
128 | This License does not grant permission to use the trade names, trademarks,
129 | service marks, or product names of the Licensor, except as required for
130 | reasonable and customary use in describing the origin of the Work and
131 | reproducing the content of the NOTICE file.
132 |
133 | 7. Disclaimer of Warranty.
134 |
135 | Unless required by applicable law or agreed to in writing, Licensor provides the
136 | Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
137 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
138 | including, without limitation, any warranties or conditions of TITLE,
139 | NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
140 | solely responsible for determining the appropriateness of using or
141 | redistributing the Work and assume any risks associated with Your exercise of
142 | permissions under this License.
143 |
144 | 8. Limitation of Liability.
145 |
146 | In no event and under no legal theory, whether in tort (including negligence),
147 | contract, or otherwise, unless required by applicable law (such as deliberate
148 | and grossly negligent acts) or agreed to in writing, shall any Contributor be
149 | liable to You for damages, including any direct, indirect, special, incidental,
150 | or consequential damages of any character arising as a result of this License or
151 | out of the use or inability to use the Work (including but not limited to
152 | damages for loss of goodwill, work stoppage, computer failure or malfunction, or
153 | any and all other commercial damages or losses), even if such Contributor has
154 | been advised of the possibility of such damages.
155 |
156 | 9. Accepting Warranty or Additional Liability.
157 |
158 | While redistributing the Work or Derivative Works thereof, You may choose to
159 | offer, and charge a fee for, acceptance of support, warranty, indemnity, or
160 | other liability obligations and/or rights consistent with this License. However,
161 | in accepting such obligations, You may act only on Your own behalf and on Your
162 | sole responsibility, not on behalf of any other Contributor, and only if You
163 | agree to indemnify, defend, and hold each Contributor harmless for any liability
164 | incurred by, or claims asserted against, such Contributor by reason of your
165 | accepting any such warranty or additional liability.
166 |
167 | END OF TERMS AND CONDITIONS
168 |
169 | APPENDIX: How to apply the Apache License to your work
170 |
171 | To apply the Apache License to your work, attach the following boilerplate
172 | notice, with the fields enclosed by brackets "[]" replaced with your own
173 | identifying information. (Don't include the brackets!) The text should be
174 | enclosed in the appropriate comment syntax for the file format. We also
175 | recommend that a file or class name and description of purpose be included on
176 | the same "printed page" as the copyright notice for easier identification within
177 | third-party archives.
178 |
179 | Copyright [yyyy] [name of copyright owner]
180 |
181 | Licensed under the Apache License, Version 2.0 (the "License");
182 | you may not use this file except in compliance with the License.
183 | You may obtain a copy of the License at
184 |
185 | http://www.apache.org/licenses/LICENSE-2.0
186 |
187 | Unless required by applicable law or agreed to in writing, software
188 | distributed under the License is distributed on an "AS IS" BASIS,
189 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
190 | See the License for the specific language governing permissions and
191 | limitations under the License.
--------------------------------------------------------------------------------