2012-11-13 2 views
55

У меня есть класс, как показано ниже:Mock конструктор с параметром

public class A { 
    public A(String test) { 
     bla bla bla 
    } 

    public String check() { 
     bla bla bla 
    } 
} 

Логика в конструкторе A(String test)check() и являются вещи, которые я пытаюсь издеваться. Мне нужны любые вызовы: new A($$$any string$$$).check() возвращает фиктивную строку "test".

Я пробовал:

A a = mock(A.class); 
when(a.check()).thenReturn("test"); 

String test = a.check(); // to this point, everything works. test shows as "tests" 

whenNew(A.class).withArguments(Matchers.anyString()).thenReturn(rk); 
// also tried: 
//whenNew(A.class).withParameterTypes(String.class).withArguments(Matchers.anyString()).thenReturn(rk); 

new A("random string").check(); // this doesn't work 

Но не кажется, что это будет работать. new A($$$any string$$$).check() все еще проходит логику конструктора вместо того, чтобы извлекать издеваемый объект A.

+0

ваша издевались проверка() метод работает правильно? –

+0

@BenGlasser check() работает нормально. Просто whenNew не работает вообще. Я также обновил описание. – Shengjie

ответ

56

кода вы вывесили работу для меня с последней версией Mockito и Powermockito. Может быть, вы не подготовили A? Попробуйте это:

A.java

public class A { 
    private final String test; 

    public A(String test) { 
     this.test = test; 
    } 

    public String check() { 
     return "checked " + this.test; 
    } 
} 

MockA.java

import static org.hamcrest.MatcherAssert.assertThat; 
import static org.hamcrest.Matchers.equalTo; 
import static org.mockito.Mockito.mock; 
import static org.mockito.Mockito.when; 

import org.junit.Test; 
import org.junit.runner.RunWith; 
import org.mockito.Mockito; 
import org.powermock.api.mockito.PowerMockito; 
import org.powermock.core.classloader.annotations.PrepareForTest; 
import org.powermock.modules.junit4.PowerMockRunner; 

@RunWith(PowerMockRunner.class) 
@PrepareForTest(A.class) 
public class MockA { 
    @Test 
    public void test_not_mocked() throws Throwable { 
     assertThat(new A("random string").check(), equalTo("checked random string")); 
    } 
    @Test 
    public void test_mocked() throws Throwable { 
     A a = mock(A.class); 
     when(a.check()).thenReturn("test"); 
     PowerMockito.whenNew(A.class).withArguments(Mockito.anyString()).thenReturn(a); 
     assertThat(new A("random string").check(), equalTo("test")); 
    } 
} 

Оба теста должны проходить с Mockito 1.9.0, 1.4.12 powermockito и JUnit 4.8.2

+13

Также обратите внимание, что если конструктор вызывается из другого класса, включите его в список в 'PrepareForTest' –

33

Насколько я знаю, вы не можете издеваться над конструкторами с mockito, только методами. Но согласно вики на кодовой странице Mockito google существует способ издеваться над конструкторским поведением, создав метод в вашем классе, который возвращает новый экземпляр этого класса. то вы можете издеваться над этим методом. Ниже приводится excerpt directly from the Mockito wiki:

Pattern 1 - с использованием методов одной строки для создания объекта

Чтобы использовать шаблон 1 (тестирование класса под названием MyClass), вы бы заменить вызов как

Foo foo = new Foo(a, b, c); 

с

Foo foo = makeFoo(a, b, c); 

и написать одну строку Metho d

Foo makeFoo(A a, B b, C c) { 
     return new Foo(a, b, c); 
    } 

Важно, чтобы в методе не было никакой логики; только одна строка, которая создает объект . Причиной этого является то, что сам метод никогда не будет отправлен .

Когда вы придете, чтобы проверить класс, объект, который вы проверите, будет действительно быть шпионом Mockito, с этим методом переопределить, чтобы вернуть макет. То, что вы тестируете, поэтому не является самим классом, а очень слегка измененной версией.

Ваш тестовый класс может содержать элементы как

@Mock private Foo mockFoo; 
    private MyClass toTest = spy(new MyClass()); 

Наконец, внутри вашего метода испытаний вы дразнить из вызова makeFoo с линией, как

doReturn(mockFoo) 
     .when(toTest) 
     .makeFoo(any(A.class), any(B.class), any(C.class)); 

Вы можете использовать matchers, более специфичный, чем any(), если вы хотите проверить аргументы, переданные конструктору.

Если вы просто хотите вернуть насмешливый объект своего класса, я думаю, что это должно сработать для вас.В любом случае вы можете прочитать больше о насмешливом создании объекта здесь:

http://code.google.com/p/mockito/wiki/MockingObjectCreation

+10

+1, мне не нравится тот факт, что мне нужно настроить исходный код, чтобы сделать его более дружелюбным к mockito. Спасибо за обмен. – Shengjie

+15

Невероятно, чтобы исходный код был более тестируемым или чтобы избежать проверки шаблонов при написании кода. Если вы пишете источник, который более подвержен тестированию, он будет автоматически более удобным. Изоляция вызовов вашего конструктора в их собственных методах - всего лишь один из способов достижения этого. –

8

Без использования Powermock. См. Пример ниже, основанный на ответе Бена Глассера, поскольку мне потребовалось некоторое время, чтобы понять это. Надеюсь, что это экономит несколько раз ...

Оригинальный Класс:

public class AClazz { 

    public void updateObject(CClazz cClazzObj) { 
     log.debug("Bundler set."); 
     cClazzObj.setBundler(new BClazz(cClazzObj, 10)); 
    } 
} 

Модифицированный Класс:

@Slf4j 
public class AClazz { 

    public void updateObject(CClazz cClazzObj) { 
     log.debug("Bundler set."); 
     cClazzObj.setBundler(getBObject(cClazzObj, 10)); 
    } 

    protected BClazz getBObject(CClazz cClazzObj, int i) { 
     return new BClazz(cClazzObj, 10); 
    } 
} 

испытаний Класс

public class AClazzTest { 

    @InjectMocks 
    @Spy 
    private AClazz aClazzObj; 

    @Mock 
    private CClazz cClazzObj; 

    @Mock 
    private BClazz bClassObj; 

    @Before 
    public void setUp() throws Exception { 
     Mockito.doReturn(bClassObj) 
       .when(aClazzObj) 
       .getBObject(Mockito.eq(cClazzObj), Mockito.anyInt()); 
    } 

    @Test 
    public void testConfigStrategy() { 
     aClazzObj.updateObject(cClazzObj); 

     Mockito.verify(cClazzObj, Mockito.times(1)).setBundler(bClassObj); 
    } 
} 
1

Mockito имеет ограничения тестирования окончательный, СТА tic и private.

с библиотекой тестирования JMockit, вы можете сделать несколько вещей очень легко и прямо вперед, как показано ниже:

Mock конструктор класса java.io.File:

new MockUp<File>(){ 
    @Mock 
    public void $init(String pathname){ 
     System.out.println(pathname); 
     // or do whatever you want 
    } 
}; 
  • общественный конструктор имя должно быть заменено на $ init
  • аргументы и исключения брошены остаются такими же
  • тип возврата должен быть определен как void

Mock статический метод:

  • удалить статический из метода макет подписи
  • метод подписи остается тем же иначе