【问题标题】:Is there a way to return a new object each time with EasyMock return anyTimes()?有没有办法使用 EasyMock return anyTimes() 每次都返回一个新对象?
【发布时间】:2021-02-25 21:46:12
【问题描述】:

我正在为一个严重依赖日历的类进行单元测试。我正在尝试模拟所有调用,以便我基本上可以将自己指定的系统时间插入到类中以进行一些日期时间逻辑测试。

这是我的第一次尝试:

Calendar fixedSystemCal = Calendar.getInstance();
fixedSystemCal.set(2021, Calendar.FEBRUARY, 22, 18, 0, 0);

PowerMock.mockStatic(Calendar.class);
EasyMock.expect(Calendar.getInstance()).andReturn(fixedSystemCal).anyTimes();
PowerMock.replay();

不幸的是,经过一番摸索,我发现这不起作用,因为日历对象在类内部发生了变异。由于这个模拟每次返回相同的日历,这是一个问题。例如:

Calendar firstCall = Calendar.getInstance(); //Feb 22
firstCall.add(Calendar.DATE, 5); //Feb 27

Calendar secondCall = Calendar.getInstance() // This is also Feb 27 now

有什么方法可以每次都取回不同的日历对象(对于任意数量的调用)?到目前为止,我发现的唯一解决方案就是像这样重复多次:

Calendar fixedSystemCal = Calendar.getInstance();
fixedSystemCal.set(2021, Calendar.FEBRUARY, 22, 18, 0, 0);

PowerMock.mockStatic(Calendar.class);
EasyMock.expect(Calendar.getInstance()).andReturn((Calendar) fixedSystemCal.clone()).andReturn((Calendar) fixedSystemCal.clone()).andReturn((Calendar) fixedSystemCal.clone());
PowerMock.replay();

我将在下一步中用 Java 时间替换此代码,但我需要进行功能性单元测试才能进行更改。

【问题讨论】:

    标签: java powermock easymock


    【解决方案1】:

    您应该能够使用andAnswer 而不是andReturn 来提供可用于返回新实例的lambda/IAnswer 实现。比如:

    EasyMock.expect(Calendar.getInstance())
       .andAnswer(() -> (Calendar)fixedSystemCal.clone());
    

    【讨论】:

      【解决方案2】:

      您需要使用andAnswer 而不是andReturn。尽管它们的名字看起来很相似,但在模拟和测试期间它们都有不同的用途。如果您需要使用静态值(总是相同的实例),请使用 andReturn。如果您需要使用动态或派生值,请使用 andAnswer。

      代码示例

      Calendar fixedSystemCal = Calendar.getInstance();
      fixedSystemCal.set(2021, Calendar.FEBRUARY, 22, 18, 0, 0);
      
      PowerMock.mockStatic(Calendar.class);
      EasyMock.expect(Calendar.getInstance()).andReturn((Calendar) fixedSystemCal.clone()).andReturn((Calendar) fixedSystemCal.clone()).andReturn((Calendar) fixedSystemCal.clone());
      PowerMock.replay();
      
      EasyMock.expect(Calendar.getInstance()).andAnswer(() -> (Calendar) fixedSystemCal.clone());
      

      然后返回

      andReturn 设置调用方法时要返回的值。该值将始终与您定义的相同实例相同。在您的情况下,它将返回 fixedSystemCal.clone() 的值,这将始终是您克隆一次的日历的同一实例。将其视为将克隆保存在变量中,并在调用方法时始终返回相同的变量。

      只有在模拟方法调用时知道返回值时才应该使用 andReturn。然后,当您调用模拟方法时,将返回此预定义值。

      如果您希望以常规代码表示。模拟一个方法getDate 看起来像这样,你总是返回相同的日历实例:

      private Calendar calendar = Calendar.getInstance();
      
      public Calendar getCalendar() {
          return calendar;
      }
      

      和Anwser

      andAnwser 将在返回值之前执行一个方法。这可以在您需要在调用模拟方法时执行其他操作时使用,例如当你需要克隆一个对象或者你想根据传递的参数执行一些逻辑时。

      如果您希望以常规代码表示。模拟一个方法getDate 看起来像这样,你总是返回一个新的日历实例:

      public Calendar getCalendar() {
          return Calendar.getInstance();
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-06-05
        • 1970-01-01
        • 2020-05-05
        • 1970-01-01
        • 2021-09-15
        • 1970-01-01
        • 2020-03-03
        • 1970-01-01
        相关资源
        最近更新 更多