JUnit издевается над Mockito, EasyMock и т. д.

Я пытаюсь издеваться над методом объекта внутри тестируемого класса.

Например

class ClassToTest {
   public doSomething () {
       SomeObject a = new SomeObject ();
       a.doSomethingElse ();
   }
}

Есть ли способ издеваться над методами переменной «а»? Я бы хотел, чтобы doSomethingElse ничего не делал во время тестирования. В настоящее время я использую Mockito, но я открыт для любых насмешливых фреймворков.

Спасибо


person Shaun    schedule 14.10.2010    source источник


Ответы (6)


Да, есть способ, как показано в следующем тесте JMockit:

public void testDoSomething(final SomeObject mock)
{
    new ClassToTest().doSomething();

    new Verifications() {{ mock.doSomethingElse(); }};
}

Нет необходимости рефакторить тестируемый код, чтобы использовать оболочку, DI и т. д.; просто издевайтесь над тем, что вам нужно, чтобы над вами издевались.

person Rogério    schedule 15.02.2011

Невозможно издеваться над ссылкой «a», когда она объявлена ​​как локальная переменная, как в вашем случае. Вы можете рассмотреть возможность внедрения зависимости в SomeObject, например. как параметр метода doSomething. Таким образом, вместо этого вы можете внедрить макет SomeObject в свой тест.

Одним из преимуществ внедрения зависимостей является повышенная тестируемость. .

person Jeroen Rosenberg    schedule 14.10.2010

С некоторым рефакторингом это возможно, конечно:

class SomeObject {
    public void doSomethingElse()
    {

    }
}

class ClassToTest
{
    private final SomeObject someObject;

    public void doSomething()
    {
        someObject.doSomethingElse();
    }

    public ClassToTest(SomeObject someObject)
    {
        this.someObject = someObject;
    }
}

class Test {
    @Test
    public void testDoSomething()
    {
        SomeObject someObject = Mockito.mock(SomeObject.class);
        new ClassToTest(someObject).doSomething();
        Mockito.verify(someObject, Mockito.atLeastOnce()).doSomethingElse();
    }
}
person Boris Pavlović    schedule 14.10.2010
comment
Да, это была и моя мысль. Я просто не был уверен, возможно ли издевательство над локальной переменной (пока) - person Shaun; 14.10.2010

Я считаю, что вы можете использовать расширения классов EasyMock для EasyMock 2.5 или более ранних версий, и, по-видимому, они включены в 3.0. См. эту часть предыдущей страницы для получения информации о том, что вы пытаетесь сделать. Тем не менее, я лично не пытался это сделать, поэтому я не знаю, насколько хорошо это сработает.

person Thomas    schedule 14.10.2010
comment
с расширениями класса EasyMock вы можете имитировать классы, где вы можете только имитировать интерфейсы без расширений класса. Однако вы не можете имитировать ссылки, объявленные как локальные переменные. - person Jeroen Rosenberg; 14.10.2010

Если вам нужен новый экземпляр в каждом вызове, я бы предложил провести рефакторинг следующим образом:

class ClassToTest {
   public doSomething () {
      SomeObject a = getInstance();
      a.doSomethingElse ();
   }
   protected SomeObject getInstance() {
      return new SomeObject();
   }
}

Затем вы можете создать тестовый класс, расширяющий ClassToTest, переопределяя метод getInstance() и предоставляя фиктивный объект.

Это, конечно, возможно только в том случае, если вы согласны с раскрытием метода getInstance(), поэтому я не рекомендую его, если класс является частью общедоступного API. Если это так, рассмотрите возможность предоставления фабричного класса с помощью внедрения зависимостей.

person Buhb    schedule 14.10.2010
comment
Если вы идете по этому пути, я думаю, что создам Provider (Factory) и введу его. Приличный DI-фреймворк (например, Guice) создаст для вас фабрику. - person Michael Lloyd Lee mlk; 14.10.2010

class ClassToTest {
    private SomethingElseInterface somethingElseDoer ;

    public ClassToTest(SomethingElseInterface somethingElseDoer) {
        this.somethingElseDoer = somethingElseDoer;
    }

    public doSomething () {
        somethingElseDoer.doSomethingElse();
    }
}

И где вы его используете:

SomethingElseInterface somethingElseDoer = ...; // in a test, this is where you mock it
ClassToTest foo = new ClassToTest(somethingElseDoer); // inject through constructor
foo.doSomething();
person Christoffer Hammarström    schedule 14.10.2010