1 2 Previous Next 16 Replies Latest reply on Jan 20, 2006 6:19 AM by Magnus Sandberg

    Unit Testing and EntityManager injection

    Marco Pancotti Newbie

      Hi to everybody and thanks for the big job you have done.

      I need an help as I'm writing my first Seam application.

      In the documentation about unit testing there is an example of a RegisterActionTest where the first line of code is :

      EntityManagerr em = getEntityManagerFactory.createEntityManager()

      Where does the getEntityManagerFactory method come from? I'm sorry if the question is trivial, but I'm new in EJB and Eclipse did not suggest me any import.

      Thanks
      Marco Pancotti
      Italy

        • 1. Re: Unit Testing and EntityManager injection
          Gavin King Master

          You have to write that method yourself. It's just standard EJB3 stuff, not Seam-specific.

          • 2. Re: Unit Testing and EntityManager injection
            Louis Coetzee Apprentice

            Is there an example of it somewhere ?

            (I have managed to get the integration test running using the microcontainer, but would ideally like to build unit tests as well).

            Thanks

            Louis

            • 3. Re: Unit Testing and EntityManager injection
              Gavin King Master

              Check the EJB3 persistence spec, there are examples there.

              • 4. Re: Unit Testing and EntityManager injection
                Louis Coetzee Apprentice

                Thanks for the pointer.

                Based on what I saw in the spec (after a very quick scan) I have implemented it as follows (assuming that the trySeam1Entity has been configured in my persistence.xml):


                public class BeginWithFactoryTestNG {
                
                 private static EntityManagerFactory emf = null;
                 public EntityManagerFactory getEntityManagerFactory() {
                 if (emf == null) {
                 emf = Persistence.createEntityManagerFactory("trySeam1Entity");
                 }
                
                 return emf;
                 }
                 @Test
                 public void testPersist() {
                
                 EntityManager em = getEntityManagerFactory().createEntityManager();
                 assert em != null;
                 FElement fe = new FElement();
                 fe.setValue("Gavin is King ;-)");
                 em.getTransaction().begin();
                 em.persist(fe);
                 em.flush();
                 em.getTransaction().commit();
                 em.close();
                 }
                 @Test
                 public void testRetrieve() {
                 EntityManager em = getEntityManagerFactory().createEntityManager();
                 .
                 .
                 }
                
                }

                Seems to work OK, so hopefully I haven't missed the bus completely !

                Thanks

                Louis

                • 5. Re: Unit Testing and EntityManager injection
                  Magnus Sandberg Novice

                  Maybe this is a pure ejb3 question but I cannot find how to to this:

                  I want to replace the EntityManager with a mocked EntityManager so that
                  my EntityManager is used for all

                  @PersistenceContext
                  injections.

                  How would I do that? Any pointers appreciated.

                  Thanks,
                  /Magnus


                  • 6. Re: Unit Testing and EntityManager injection
                    Gavin King Master

                    What do you mean by a "mock" EntityManager. It is very unusual - but perfectly possible - to mock out an EM. But perhaps "mock" is not really what you mean...

                    • 7. Re: Unit Testing and EntityManager injection
                      Magnus Sandberg Novice

                      What I mean is I want to use a EntityManager that basically just returns what I tell it to return without accessing the database, this to test code given a test scenario without having to access a database.

                      One such "mock" is to make persist() just do nothing or make it fail ...

                      This would to very usefull when testing certain database inserts that needs a lot of data already in the database without having to populate the database in advance.

                      /Magnus

                      • 8. Re: Unit Testing and EntityManager injection
                        Gavin King Master

                        Oh OK, apologies, that is truly a mock.

                        So, just instantiate one and inject it into your components ;-)

                        • 9. Re: Unit Testing and EntityManager injection
                          Magnus Sandberg Novice

                          Hmm ... yes ... not that I'm sure how to do that ... an example would be nice.

                          I would still like the test to run in the microcontainer so that some object still uses a "real" EntityManager, if that is this possible? When should I inject my EM so that the microcontainer doesn't inject its EM after mine?

                          Thanks,
                          /Magnus

                          • 10. Re: Unit Testing and EntityManager injection
                            Gavin King Master

                            Oh if you are running EEJB its a bit different. It seems to me very strange to do mocking when running integration tests though. I would recommend:


                            (1) Mocking for unit tests (no mc or EEJB)
                            (2) No mocking for integration tests (mc/EEJB)

                            • 11. Re: Unit Testing and EntityManager injection
                              Magnus Sandberg Novice

                              Really? A concrete example of what I would like to do, would be to run the "RegisterTest" with a mocked em instance, to test that the session-bean-logic and the navigation flow is working as expected, but without actually insering anything into any database.

                              This (imho) should be very usefull if the "register.register()" call does some validation that needs testing and/or the data insertion into the database requires that data is already present in the database (roles, groups etc).

                              Do you in this case mean that I should run this test without mc/EEJB? If so how do I inject my mocked em?

                              Thanks
                              /Magnus

                              • 12. Re: Unit Testing and EntityManager injection
                                Gavin King Master

                                Well, the thing is, if you run inside MC, you would have to mock out the EM *inside* the MC. This is very easy to do with a plain MC, but not really with EEJB.

                                I would try asking in the EJB3 forum, perhaps I am missing something.

                                But I really think it is very wierd to mock the database in integration tests. It is much, much better to actually test that the data is getting all the way to the db.


                                Now for *unit* tests, all you do is just create an EM and set the attribute of your bean. Its trivial.

                                LoginAction la = new LoginAction();
                                la.setEntityManager(mockEntityManager);
                                la.login();

                                or whatever.

                                If you are using instvar injection rather than setter injection, just use reflection to do it.

                                • 13. Re: Unit Testing and EntityManager injection
                                  Magnus Sandberg Novice

                                   


                                  But I really think it is very wierd to mock the database in integration tests. It is much, much better to actually test that the data is getting all the way to the db.


                                  I have to disagree, just because you want to test the interaction between two objects it does not necessarily mean that you (also) want to test the interaction with the database.

                                  I guess that I can solve this quite nicely by running the tests where I don't want database interaction outside the mc by injecting my own em and also run another set of test inside the mc for database integration testing.

                                  It would be nice if SeamTest could help with this ;-) but I can manage on my own ... maybe I'm the only one that want to do this ...

                                  Thanks,
                                  /Magnus

                                  • 14. Re: Unit Testing and EntityManager injection
                                    Magnus Sandberg Novice

                                    I'm back after some playing around and I could really use some pointers.

                                    I have done some tests using SeamTest trying to use my own EM but I cannot get it to work. This is mainly because 'Component.getInstance()' returns a Proxy and therefore I cannot replace the EM in the returned instance. When setting my own instance in the Context no injection takes place so other variables that need values remains empty.

                                    Is there any way to solve this? I have two ideas:
                                    1. Patch SeamTest/Component (or?) so that the EM can be replaces.
                                    2. Somehow force SeamTest/Component (or?) to inject values in the object that I set in the Context.

                                    Even though I know that you don't like what I'm trying to do I would deeply appreciate some insightful help here.

                                    Thanks,
                                    /Magnus

                                    1 2 Previous Next