8 Replies Latest reply on Apr 25, 2008 10:12 AM by ssilvert

    How to overwrite a bean class with a mock object

    zhen_jane

      Hi folks,

      I understand that JSFUnit will automatically generate all request and session beans after receiving a JSFCLientSession request through following function calll:

      JSFClientSession client=new JSFClientSession("someViewID");

      but the problem is in case the beans go to a database to fetch the data, I would like to use a mock bean to wrap some fake data. How should I do it?

      thanks

        • 1. Re: How to overwrite a bean class with a mock object
          ssilvert

          Interesting approach. Can you tell me more about why you don't want to let the managed bean work as designed during your test? I'm sure you have a good reason, but I don't understand why the mock is needed. Maybe DBUnit combined with JSFUnit would be a good choice?

          JSFUnit doesn't actually generate any request and session beans. It merely keeps the FacesContext alive so that you have access to the beans using EL just as you would during a JSF request.

          Any solution to your mock bean problem would involve knowing if you were accessing the bean during a regular JSF request or fetching a value during JSFUnit testing.

          You can look for the presence of a cookie to tell if you are using JSFUnit. That cookie is called "org.jboss.jsfunit.framework.WebConversationFactory.testing_flag". You can check it with FacesContext.getExternalContext().getRequestCookieMap().

          Stan

          • 2. Re: How to overwrite a bean class with a mock object
            zhen_jane

            Hi Stan,

            Thanks for the tips.

            It's just that I wanted to run the tests without the database, or even disturbing the database by changing/deleting operation. With checking cookies, I think this would give me a solution. I can add some code to the "real code" to check this testing mode, if the testing mode is on, I'll reroute the function call to get some fake data.

            Just not sure if someone else would be happy by introducing this kinda testing logic to real code. But anyway, thanks again for the nice answer.

            • 3. Re: How to overwrite a bean class with a mock object
              ssilvert

               

              "zhen_jane" wrote:

              Just not sure if someone else would be happy by introducing this kinda testing logic to real code. But anyway, thanks again for the nice answer.


              Yes, that's why I suggested DBUnit. I've never used it myself, but it appears to be made for solving your kind of problem.

              Stan

              • 4. Re: How to overwrite a bean class with a mock object
                zhen_jane

                One more point is that when running unit test, we want to just test certain classes, but DAO classes are always under these tested classes. The in-container test framework is good in it tests both jsp pages and beans, however, it has the drawback not to allow substitution of DAO objects with mock objects since all objects are created in one batch. This would introduce more dependency than unit testing should be...or it's more like the functional test. So I feel in order to make JSFUnit become the real unit testing framework, it has to have this mock object insertion function.

                • 5. Re: How to overwrite a bean class with a mock object
                  ssilvert

                  Another thought occurred to me. Since you are wanting to mock the managed beans, could you just use a different faces-config.xml for testing? In the test version, you would just bind the mocks to the EL names.

                  Production faces-config.xml:

                  <managed-bean>
                   <description>Backing bean for foo</description>
                   <managed-bean-name>foo</managed-bean-name>
                   <managed-bean-class>org.mycompany.Foo</managed-bean-class>
                   <managed-bean-scope>session</managed-bean-scope>
                   </managed-bean>


                  faces-config.xml for testing:
                  <managed-bean>
                   <description>Mock backing bean for foo</description>
                   <managed-bean-name>foo</managed-bean-name>
                   <managed-bean-class>org.mycompany.mock.MockFoo</managed-bean-class>
                   <managed-bean-scope>session</managed-bean-scope>
                   </managed-bean>
                  

                  Stan

                  • 6. Re: How to overwrite a bean class with a mock object
                    zhen_jane

                    HI Stan,
                    I thought about this. I can use Ant to replace these files. But one thing occurred to me is that the mock objects are subjected to change a lot. For instance, when I test a class, I might need a set of mock data, and when testing another, I would need to add another set of mock data. It's this kinda factor that would cause running JSF tests to be slow (in my case, I have to get out of Eclipse to manually deploy war. For some reason, the previous developer created the JSP page structure different from the source code one, for instance, a jsp page is in war file under myWebApp/a/b, but in eclipse, it's in ../c directory. It seemed when I run test in Eclipse, it always go to ../c to find jsp pages; while the view IDs are all /a/b/.. ... anyway). Unless I find a solution for this, I wouldn't want to run in-container test cases because TDD is all about write a bit run a bit (as far as my undestanding). It seems pretty painful for me.

                    A better solution might be to divide the test into two stages. First, use the mock libraries (JSFUnit also provides one) to test the backing beans isolated from DAO (DAO would have been tested ahead too). So based on these two tests, running JSFUnit on top would make some sense for testing JSP pages and all JSF navigation functions stuff.

                    • 7. Re: How to overwrite a bean class with a mock object
                      zhen_jane

                      All what I meant was since in-container tests need to deploy war, it will involve building the whole project. With a frequent change on mock classes on the way writing test cases, it would be a pain if this project takes some time to build.

                      Is there some AOP programming technique would allow only test code to be built and deployed leaving existing product war untouched, yet still able to test that?

                      I used a tool before, it reverse-engineers a war and create the calling stack graph, etc. Just a thought

                      • 8. Re: How to overwrite a bean class with a mock object
                        ssilvert

                         

                        "zhen_jane" wrote:
                        But one thing occurred to me is that the mock objects are subjected to change a lot.


                        True. This is one reason that I advocate not using mocks at all. IMHO, mock data belongs in a database. This way, you can run real tests using real objects in a real container. You never have to worry about keeping a mock library up to date and you never have to worry about the fact that your mocks might be causing a test to fail.

                        I think that the use of mock objects has really been driven by the fact that in-container testing was cumbersome and slow. However, that is now changing. We now have containers that boot up in less than a second. For deployment, you can use exploded versions of your WAR so you don't actually have to jar anything up. Tools like Cargo even allow you to easily test your application against many different containers with minimal configuration.

                        JSFUnit uses JSFUnit for its testing. I do TDD for every bit of code I write. So I know that this is a very viable way to do testing. I can now run JSFUnit tests against 6 different containers using Cargo and Maven.

                        Other developers are using JSFUnit with Ant to accomplish the same thing.

                        So we all need to rethink the possibilities when it comes to testing. The closer you are to testing the true production environment the better. And the latest tools are making in-container testing without mocks into a very attractive option.

                        Stan