2011-12-28 5 views
6

Я пишу модульные тесты для сервисного уровня в своем весеннем приложении.
Вот мой класс обслуживанияТестирование модуля с помощью Mockito

@Service 
    public class StubRequestService implements RequestService {  
     @Autowired 
     private RequestDao requestDao; 

     @Transactional(propagation = Propagation.REQUIRED, readOnly = true) 
     @Override 
     public Request getRequest(Long RequestId) { 
      Request dataRequest = requestDao.find(requestId); 
      return dataRequest; 
     } 
    } 

Вот мой тестовый класс

@RunWith(MockitoJUnitRunner.class) 
@ContextConfiguration(locations = { "/META-INF/spring/applicationContext.xml" }) 
public class StubRequestServiceTest { 

    @Mock 
    public RequestDao requestDao; 

    StubRequestService stubRequestService; // How can we Autowire this ? 

    @org.junit.Before 
    public void init() { 
     stubRequestService = new StubRequestService(); // to avoid this 
     stubRequestService.setRequestDao(dataRequestDao); 
     // Is it necessary to explicitly set all autowired elements ? 
     // If I comment/remove above setter then I get nullPointerException 
    } 

    @Test 
    public void testGetRequest() { 
     Request request = new Request(); 
     request.setPatientCnt("3"); 
     when(requestDao.find(anyLong())).thenReturn(request); 
     assertEquals(stubRequestService.getRequest(1234L).getPatientCnt(),3); 
    }  
} 

Its работает нормально, но у меня есть несколько вопросов

  1. Как мы можем Autowire класс обслуживания в тесте? Я использую конструктор в методе init() для создания объекта службы.
  2. Нужно ли устанавливать весь элемент Autowire для класса обслуживания? Для ex StubRequestService имеют автоподбор RequestDao, который я должен установить явно перед вызовом метода тестирования, иначе он дал nullPointerException, поскольку requestDao - null в StubRequestService.getRequest.
  3. Каковы хорошие практики, которые следует выполнять при модульном тестировании? (Если я делаю что-то неправильно).
+0

Если вы измените свой вопрос после того, как ответы даны, ответы не имеет смысла больше. Я откажусь от последнего изменения. –

+0

@JB: Извинения за редактирование вопроса. Я просто хотел предоставить правильную и точную информацию. Спасибо – xyz

ответ

3
  1. Если вы действительно чувствуете, что это облегчит понимание ваших тестов, вы можете инициализировать весенний контекст и получить все объекты оттуда. Однако, как правило, для создания тестов потребуется отдельный отдельный файл конфигурации Spring Spring, поэтому я бы не рекомендовал его.

    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("testApplicationContext.xml"); 
    stubRequestService = (RequestService)applicationContext.getBean("myRequestServiceBean"); 
    
  2. (и 3) В принципе, я предпочитаю тестирование каждого компонента моего приложения в полной изоляции от друг друга, и именно поэтому я не рекомендую то, что я описал в работе [1].

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

Допустим, у вас есть три класса:

//Fetches stuff from some webservice and converts to your app domain POJOs 
class DataAccessLayer { 
    public void setWebservice(Webservice ws) {...}; 

    public MyObject getMyObject() {...}; 
} 

//Formats the domain POJOs and sends them to some kind of outputstream or stuff. 
class ViewLayer { 
    public void setOutputStream(OutputStream os) {...}; 

    public void viewMyObject(MyObject mo) {...}; 
} 

//Main entry point of our MyObject fetch-process-display workflow 
class Controller { 
    public void setDataAccessLayer(DataAccessLayer dal) {...}; 
    public void setViewLayer(ViewLayer vl) {...}; 

    public void showMyObject() { 
     MyObject mo = dal.getMyObject(); 
     ...some processing here maybe... 
     vl.viewMyObject(mo); 
    } 
} 

Теперь, какие тесты мы можем написать здесь?

  1. тест, если DataAccessLayer правильно преобразует объект из издевались до WS для нашего объекта домена.
  2. Протестируйте, если ViewLayer правильно форматирует предоставленный ему объект и записывает его в moreded up Выходной поток.
  3. тест, если Controller принимает объект от издевались доDataAccessLayer обрабатывает его должным образом и посылает его Посмешищем доViewLayer.
+0

Есть ли конкретная причина использовать другой файл контекста для создания экземпляра компонента в тесте? И спасибо, например. Это очень помогло. – xyz

+0

Нет причин, просто так бывает, что это несовместимо с вашими тестами. Например, это требует некоторых ресурсов JNDI, возможно, загружает некоторые базы данных (и тесты никогда не используют их), может быть, некоторая безопасность. Поэтому в конце вы просто начинаете замечать, что проще создать отдельный файл контекста для тестирования. – bezmax

+0

Да, есть причина: вы не хотите тестировать службу с реальным DAO. Вы хотите, чтобы DAO тестировал сервис. Но следуйте советам Макса и моим: не используйте контекст Spring для тестирования модулей. Возможно, вам понадобится контекст Spring, который будет внедрять Datasource, SessionFactory и TxManager в тестах DAO, но не в тесте на обслуживание. –

7

Ваш тест в порядке. Он даже не должен содержать аннотацию @ContextConfiguration.

Целевая часть фреймворков инъекций зависимостей, таких как Spring, состоит в том, чтобы иметь возможность выполнять тестовые службы, просто создавая их экземпляр, устанавливая макетные зависимости, а затем вызывайте их методы.

Вы делаете это правильно. Для таких модульных тестов вам не нужен контекст Spring. Вот почему они называются модульными тестами: они тестируют его в изоляции от всех их фактических зависимостей, включая Spring.

Замечание: если вы используете JUnit, аргументы метода assertXxx должны быть заменены. Ожидаемое значение приходит до фактического значения. Это становится важным, когда утверждение терпит неудачу, и у вас есть сообщение вроде «ожидая 6, но было 3», а не «ожидая 3, но было 6».

+0

Спасибо за ответ и предложение. Означает ли это, что мы должны явно создать объект службы и установить все автообновленные зависимости? Мне советуют автоупроверить его, а не устанавливать его вручную. – xyz

+1

Автоустановка в порядке при запуске приложения. При модульном тестировании это не нужно или даже желательно, так как каждый тест захочет ввести свои собственные издевательства. –

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