Имитация как статических, так и динамических методов с помощью PowerMock

скажем, у нас есть

public class Foo {
   public static Foo getInstance() {...}

   public Bar bar(Baz baz) {...}
}

Что я хочу сделать, так это издеваться над этим в своих модульных тестах. Мне нужно издеваться как над статическими, так и над динамическими методами класса Foo. Издеваться над getInstance() так же просто, как

import static org.powermock.api.easymock.PowerMock.replace;
import static org.powermock.api.easymock.PowerMock.method;

public class MyTest {

   @Test
   public void myTest() {
      replace(method(Foo.class, "getInstance"))
         .with(method(MyTest.class, "getMockInstance"));
   }

   public static Foo getMockInstance() {
      Foo foo = EasyMock.createMock(Foo.class);
      EasyMock.replay(foo);
      return foo;
   }
}

Вопрос в том, как издеваться над методом bar?

Предыдущий трюк с replace(method(...)).with(method(...)) не работает, так как он не предназначен для динамических методов.

Попытка издеваться над уже издевательским классом также не работает:

...
@Test
public void myTest() {
      replace(method(Foo.class, "getInstance"))
         .with(method(MyTest.class, "getMockInstance"));

      Foo foo = Foo.getInstance();  // works well
      Baz baz1 = new Baz();
      Baz baz2 = new Baz();
      EasyMock.expect(foo.bar(baz1)).andReturn(baz2);  // exception thrown
      EasyMock.replay(foo);
}
...

Код выше выдает AssertionError: Unexpected method call bar.

Итак, как мне сделать оба? Я не хочу помещать насмешку над .bar(...) в getMockInstance, потому что в реальном мире мне нужны некоторые данные, недоступные из статического метода getMockInstance.


person mindas    schedule 02.02.2011    source источник


Ответы (1)


Я думаю, проблема в том, что вы дважды вызываете повтор на своем макете foo, один раз в статическом методе getMockInstance() и один раз после того, как вы сообщаете foo, чтобы ожидать вызова foo.bar(bar1). Попробуйте изменить getMockInstance() на

   public static Foo getMockInstance() {
      Foo foo = EasyMock.createMock(Foo.class);
      return foo;
   }

а затем сказать EasyMock воспроизвести foo после того, как вы скажете ему ожидать вызова метода bar. Итак, MyTest.java будет выглядеть примерно так:

@Test
public void myTest() {
      replace(method(Foo.class, "getInstance"))
         .with(method(MyTest.class, "getMockInstance"));

      Foo foo = Foo.getInstance();  // works well
      Baz baz1 = new Baz();
      Baz baz2 = new Baz();
      EasyMock.expect(foo.bar(baz1)).andReturn(baz2);  // exception thrown
      EasyMock.replay(foo);
}

  public static Foo getMockInstance() {
      Foo foo = EasyMock.createMock(Foo.class);
      return foo;
   }
person BuffaloBuffalo    schedule 02.02.2011
comment
Спасибо, это сработало. Можно ли добиться того же, не подавляя повтор (например, переключить Foo обратно в другой режим, добавить больше фиктивных вещей и вернуться к воспроизведению в конце)? - person mindas; 02.02.2011
comment
Документация easymock заставляет меня поверить, что нет (easymock.org/api/easymock /3.0/org/easymock/IMocksControl.html). Я думаю, что «лучшей практикой» является настройка ваших тестов в следующем порядке: 1. создавать макеты и ожидать вызовов. 2. Переиграйте все свои макеты. 3. Выполните фактические методы. 4. При необходимости вызовите EasyMock.verify. К сожалению, тестирование статических методов всегда сложно - person BuffaloBuffalo; 02.02.2011
comment
Еще раз спасибо BuffaloBuffalo за вашу помощь. - person mindas; 02.02.2011