2010-09-07 4 views
43

Моего код:пружина 3 и JUnit автоматического связывания тестирования

@Component 
public class A { 
    @Autowired 
    private B b; 

    public void method() {} 
} 

public interface X {...} 

@Component 
public class B implements X { 
    ... 
} 

Я хочу проверить в классе изоляции А. Должен ли я макет класса B? Если да, то как? Потому что он автоуведомлен, и нет сеттера, где я мог бы отправить насмешливый объект.

ответ

81

Я хочу проверить в классе изоляции А.

Вы должны абсолютно фиктивный B, а не экземпляр и впрыснуть экземпляр B. Дело в том, чтобы проверить A или нет B работ, так вы не должны допускать, чтобы потенциально поврежденный B мешал тестированию A.

При этом я настоятельно рекомендую Mockito. Как издевательские рамки идут, он чрезвычайно прост в использовании. Вы бы написать что-то вроде следующего:

@Test 
public void testA() { 
    A a = new A(); 
    B b = Mockito.mock(B.class); // create a mock of B 
    Mockito.when(b.getMeaningOfLife()).thenReturn(42); // define mocked behavior of b 
    ReflectionTestUtils.setField(a, "b", b); // inject b into the B attribute of A 

    a.method(); 

    // call whatever asserts you need here 
} 
+32

+1 для насмешки getMeaningOfLife() до 42 :-). – Dave

+11

С новой версией Mockito я бы использовал аннотацию '@ InjectMocks' в объявлении' A' и избавился от отражения 'setField (..)' – Snekse

+0

Но a является компонентом, то есть прокси (созданным с АОП). Это не удастся. Я пробовал что-то подобное, и ошибка заключалась в том, что поле b не может быть найдено на A (потому что это прокси). –

15

Вы можете ввести поле через отражение, используя Spring ReflectionTestUtils.setField (или расширение junit PrivateAccessor), или вы можете создать контекст приложения и загрузить его. Хотя для простого теста (неинтеграции) я предпочитаю использовать отражение для простоты.

0

This forum discussion имеет смысл для меня. Вы можете объявить своего частного члена b как тип интерфейсаB, который реализуется классом B (т. Е. Сервисно-ориентированным), а затем объявить класс MockB, который также реализует тот же интерфейс. В контексте приложения тестовой среды вы объявляете класс MockB и ваш прикладной контекст приложения, который вы объявляете обычным классом B, и в любом случае код для класса A не нужно изменять, поскольку он будет автоматически подключен.

+1

С @Autowire вы не объявлять бобы в контексте приложения, они просто здесь, в пути к классам. Таким образом, это решение не работает. – Damien

+0

Это решение работает, если вы подключаете bean byType (в 2.5) или объявляете квалификатор (3.0). В Spring 2.5 вы можете autowire к bean-компоненту, объявленному в вашей конфигурации контекста XML-приложения, как это можно прочитать в документации http://static.springsource.org/spring/docs/2.5.x/reference/beans.html#beans-factory- autowire. В Spring 3.0 они по-прежнему позволяют вам делать это с помощью аннотации @Qualifier (задокументировано по адресу http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/beans.html#beans- autowired-аннотаций). – Aaron

18

Вот пример того, как я получил мои тесты работы с Spring 3.1, JUnit 4.7 и 1.9 Mockito:

FooService.java

public class FooService { 
    @Autowired private FooDAO fooDAO; 
    public Foo find(Long id) { 
     return fooDAO.findById(id); 
    } 
} 

FooDAO.java

public class FooDAO { 
    public Foo findById(Long id) { 
     /* implementation */ 
    } 
} 

FooServiceTest.java

@RunWith(MockitoJUnitRunner.class) 
public class FooServiceTest { 
    @Mock private FooDAO mockFooDAO; 
    @InjectMocks private FooService fooService = new FooService(); 

    @Test public final void findAll() { 
     Foo foo = new Foo(1L); 
     when(mockFooDAO.findById(foo.getId()).thenReturn(foo); 

     Foo found = fooService.findById(foo.getId()); 
     assertEquals(foo, found); 
    } 
} 
+6

Если вы не используете 'MockitoJUnitRunner', важно помнить в' FooServiceTest': \t '@Before \t общественных недействительные initMocks() { \t \t MockitoAnnotations.initMocks (это); \t} ' – TalkLittle

Смежные вопросы