thinking

          one platform thousands thinking

          Mocking Static Calls

          How can you test methods that contain static method calls? This is a question we're facing at the moment while working on an application of which parts have been written by another development team. In order to gain insight into functionality and quality of the codebase, we are writing JUnit tests. But a lot of the code is dependent on either the JSF FacesContext or the Spring ApplicationContext being available.

          It is however impossible to mock static method calls like FacesContext.getCurrentInstance(). So how do we go around testing these calls out of container? We've thought up three different approaches, but each has its pros and cons. Let us first take a look at these three approaches...

          1. Extract method
          Introduce a method in each class that looks like the following:

           
          protected FacesContext getFacesContext() {
          return FacesContext.getCurrentInstance();
          }
           

          This can be easily mocked out in your test by creating the class with an overridden method, as follows:

           
          FacesContext mockContext = EasyMock.createMock(FacesContext.class);
          new MyObjectUnderTest() {
          protected FacesContext getFacesContext() {
          return mockContext;
          }
          }
           

          Pros

          • Easy to refactor using extract method

          Cons

          • Lots of code duplication

          2. Static Helper
          Our second option is to introduce a static helper class which has the following implementation:

           
          public class FacesContextHelper {
          private static FacesContext context;
           
          public static FacesContext getCurrentFacesContext() {
          return context != null ? context : FacesContext.getCurrentInstance();
          }
           
          public static void setFacesContext(FacesContext facesContext) {
          context = facesContext;
          }
           
          public static void reset() {
          context = null;
          }
          }
           

          Now in a testclass we can just write down the following line to mock out the FacesContext:

           
          FacesContextHelper.setFacesContext(EasyMock.createMock(FacesContext.class));
           

          Pros

          • No real painful code-duplication
          • Easy to do search-replace to convert all calls to FacesContext.getCurrentInstance() to FacesContextHelper.getCurrentFacesContext().

          Cons

          • Never forget to call reset() in the teardown of your test to prevent another test from picking up your mock.
          • Doesn't feel right to write static setter methods in your code just to enable testing it. Not an OO approach?

          3. OO Helper class
          Our third and last option is to introduce an interface and implementation of the FacesContextHelper:

           
          public interface FacesContextHelper {
          FacesContext getCurrentFacesContext();
          }
           
          public class FacesContextHelperImpl implements FacesContextHelper {
          public FacesContext getCurrentFacesContext() {
          return FacesContext.getCurrentInstance();
          }
          }
           

          We now need to introduce an instance of the FacesContextHelperImpl to each class. For this example, we will use a package protected variable in each class. It is of course also possible to use a setter method. For our test cases we now need to introduce a new FacesContextHelper:

           
          public class MockFacesContextHelper implements FacesContextHelper {
          private FacesContext mockContext;
           
          public MockFacesContextHelper(FacesContext mockContext) {
          this.mockContext = mockContext;
          }
           
          public FacesContext getCurrentFacesContext() {
          return this.mockContext;
          }
          }
           

          In our test cases we can now easily mock out the FacesContext again by setting the package protected field:

           
          someClazz.facesContextHelper = new MockFacesContextHelper(EasyMock.createMock(FacesContext.class));
           

          Pros

          • Feels more natural and OO than the static helper solution

          Cons

          • Need to introduce a new field to each and every class which needs the FacesContext mocked out.

          That's it. I myself am still doubting as to which method is the lesser evil, not one feels absolutely right. What do you think, which method do you consider better? Did I overlook another option perhaps?

          posted on 2010-02-25 09:12 lau 閱讀(350) 評(píng)論(0)  編輯  收藏 所屬分類: Unit Test


          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 达尔| 澄江县| 武邑县| 昌黎县| 拜泉县| 乐东| 遂昌县| 康乐县| 台南市| 汽车| 聂拉木县| 民权县| 栾川县| 新巴尔虎左旗| 门头沟区| 蒲江县| 莱西市| 清水河县| 怀集县| 茌平县| 和林格尔县| 奉节县| 普洱| 云霄县| 环江| 五台县| 西华县| 张家界市| 革吉县| 易门县| 青神县| 稻城县| 宜州市| 潼关县| 南华县| 揭阳市| 大理市| 麻城市| 铅山县| 内乡县| 上饶县|