java: how to mock Calendar.getInstance()?

前端 未结 6 783
忘了有多久
忘了有多久 2020-12-03 16:54

In my code I have something like this:

private void doSomething() {
   Calendar today = Calendar.getInstance();
   ....
}

How can I \"mock\

相关标签:
6条回答
  • 2020-12-03 17:16

    Write a class called DateHelper with a method getCalendar that returns Calendar.getInstance(). Refactor the class that you're testing so that it has a member variable of type DateHelper, and a constructor that injects that member variable. Use that constructor in your test, to inject a mock of DateHelper, in which getCalendar has been stubbed to return some known date.

    0 讨论(0)
  • 2020-12-03 17:20

    As far as I see it you have three sensible options:

    1. Inject the Calendar instance in whatever method/class you set that day in.

      private void method(final Calendar cal) { Date today = cal.getTime(); }

    2. Use JodaTime instead of Calendar. This is less an option and more a case of a suggestion as JodaTime will make your life a lot easier. You will still need to inject this time in to the method.

      DateTime dt = new DateTime();

      Date jdkDate = dt.toDate();

    3. Wrap Calendar inside some interface that allows you to fetch the time. You then just mock that interface and get it to return a constant Date.

      Date today = calendarInterfaceInstance.getCurrentDate()

    0 讨论(0)
  • 2020-12-03 17:20

    Using Mockito and PowerMockito:

    Calendar endOfMarch = Calendar.getInstance();
    endOfMarch.set(2011, Calendar.MARCH, 27);
    PowerMockito.mockStatic(Calendar.class);
    Mockito.when(Calendar.getInstance()).thenReturn(endOfMarch);
    

    Refer to the link for the complete code.

    0 讨论(0)
  • 2020-12-03 17:22

    You can mockit using JMockit. Here you can see how you can do it: Mock Java Calendar - JMockit vs Mockito.

    0 讨论(0)
  • 2020-12-03 17:30

    You can mock it using PowerMock in combination with Mockito:

    On top of your class:

    @RunWith(PowerMockRunner.class)
    @PrepareForTest({ClassThatCallsTheCalendar.class})
    

    The key to success is that you have to put the class where you use Calendar in PrepareForTest instead of Calendar itself because it is a system class. (I personally had to search a lot before I found this)

    Then the mocking itself:

    mockStatic(Calendar.class);
    when(Calendar.getInstance()).thenReturn(calendar);
    
    0 讨论(0)
  • 2020-12-03 17:40

    Don't mock it - instead introduce a method you can mock that gets dates. Something like this:

    interface Utility {
    
        Date getDate();
    }
    
    Utilities implements Utility {
    
    
        public Date getDate() {
    
            return Calendar.getInstance().getTime();
        }
    
    }
    

    Then you can inject this into your class or just use a helper class with a bunch of static methods with a load method for the interface:

    public class AppUtil {
    
        private static Utility util = new Utilities();
    
        public static void load(Utility newUtil) {
    
             this.util = newUtil;
        }
    
        public static Date getDate() {
    
            return util.getDate();
        }
    
    }
    

    Then in your application code:

    private void doSomething() {
       Date today = AppUtil.getDate();
       ....
    }
    

    You can then just load a mock interface in your test methods.

    @Test
    public void shouldDoSomethingUseful() {
         Utility mockUtility = // .. create mock here
         AppUtil.load(mockUtility);
    
         // .. set up your expectations
    
         // exercise the functionality
         classUnderTest.doSomethingViaAPI();
    
         // ... maybe assert something 
    
    }
    

    See also Should you only mock types you own? and Test smell - everything is mocked

    0 讨论(0)
提交回复
热议问题