it-swarm.com.ru

Как бороться с Setter/Getter-Methods от Mocks?

Так что у меня все еще есть проблемы с использованием Mockito. Итак, давайте предположим, что у меня есть следующий класс (Пожалуйста, игнорируйте логику или ее структуру, это просто короткий пример, который я создал из другого класса, с другими именами и т.д.):

public class Restaurant(
    @Autowired
    private CustomerService customerService;

    private CustomerInputData updateCustomer(CustomerInputData inputData){
        String customerId = inputData.getID();
        Customer customer = customerService.getCustomerById(customerID);
        if(customer.getAddress() != null){
            inputData.setCustomerName(customer.getCustomerName());
            inputData.setCustomerCity(customer.getCustomerCity);
            inputData.setCustomerLanguage(customer.getLanguage);
        }

        return inputData
    }
}

Итак, мое понимание юнит-тестов состоит в том, чтобы изолировать все зависимости. Здесь я хотел бы иметь клиентский класс и клиентский сервис. 

Итак, чтобы написать тестовый класс, я бы сейчас сделал следующее:

public class RestaurantTest()
{
    @Mock(name="customerService");
    private CustomerService customerService;

    @InjectMocks
    private Restaurant classUnderTest;

    @Before
    public void setUp(){
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void updateCustomer_WithValidInput_ShouldReturnUpdatedInput(){
        //Some Mocking first
        String customerId = "customerId";
        Customer customer = mock(Customer.class);
        CustomerInputData = mock(CustomerInputData.class);

        doReturn(customer).when(customerService.getCustomerById(any(String.class)));
        doReturn(customerId).when(inputData.getId());

        doReturn("address").when(customer.getAddress());
        doReturn("Name").when(customer.getName());
        doReturn("City").when(customer.getCity());
        doReturn("Language").when(customer.getLanguage());

        doNothing().when(inputData).setCustomerName(any(String.class));
        doNothing().when(inputData).setCustomerCity(any(String.class));
        doNothing().when(inputData).setCustomerLanguage(any(String.class));

        verify(customer.getAddress(), atLeastOnce());
        verify(customer.getName(), atLeastOnce());
        //and so on...

        verify(inputData, atLeastOnce()).setCustomerName(eq("Name"));
        verify(inputData, atLeastOnce()).setCustomerCity(eq("City"));
        verify(inputData, atLeastOnce()).setCustomerLanguage(eq("Language");

    }
}

Так что в настоящее время у меня нет Assert, я только проверяю, правильно ли вызваны методы. Причина, по которой я пытаюсь сделать это так, и не позволяю классу Test вызывать метод установки/получения, заключается в изоляции. Давайте предположим, что inputData.setCustomerCity не работает, мой тест не пройден. Так что это зависит от класса CustomerInputData-Class. 

Теперь, как мне подойти к этим геттерам и сеттерам, какова лучшая практика? 

Разве я не достаточно хорошо понял Мокито? Когда я использую mock (), могу ли я просто использовать setter-методы и gethods, и не нужно беспокоиться об использовании doReturns и так далее?

Я знаю, что это тест на «белый ящик», я знаю методы и то, что происходит.

7
user5417542

Только издеваться над вещами, которые вы не можете создать или пройти через себя. Do not высмеивать любые переданные объекты; предоставление поддельной версии часто намного лучше.

В этом сценарии мы можем избежать нескольких вещей, так как мы знаем несколько вещей о нашем тесте:

  • Мы получаем экземпляр Customer из customerService, но нам не нужно выполнять какую-либо проверку этого экземпляра.
  • Мы имеем, чтобы смоделировать customerService, так как это внедренная зависимость.

В свете этих двух вещей, мы должны смоделировать CustomerService, что вы делаете довольно успешно - поскольку поле названо одинаково, вам не нужны дополнительные метаданные в аннотации.

@Mock
private CustomerService customerService;

Вам также следует использовать тестовый прогон, поставляемый с Mockito, чтобы вам не пришлось явно инициализировать макеты.

@RunWith(MockitoJUnitRunner.class)
public class RestaurantTest {
    // tests
}

Теперь перейдем к фактическому юнит-тесту. Единственное, что действительно отстой, - это то, что вы должны предоставить экземпляр Customer для использования, но кроме этого, это не так уж плохо. Наши данные являются экземпляром CustomerData, который мы хотим изменить, и Customer, который мы предоставляем для тестирования. Затем мы должны просто подтвердить значения, которые нас интересуют, для нашего тестового экземпляра CustomerData.

@Test
public void updateCustomer_WithValidInput_ShouldReturnUpdatedInput(){
    //given
    final Customer customer = new Customer();
    customer.setId("123");
    customer.setAddress("Addr1");
    customer.setName("Bob");
    customer.setCity("St8")
    customer.setLanguage("Java");

    final CustomerInputData inputData = new CustomerInputData();
    inputData.setId(customer.getId());

    //when
    when(customerService.getCustomerById(customer.getId())).thenReturn(customer);
    classUnderTest.updateCustomer(customerData);

    //then
    verify(customerService.getCustomerById("123"));
    assertThat(customerData.getCustomerName(), equalTo(customer.getName()))
    // and so forth
}
7
Makoto

Это не «правильный» способ добиться этого, поскольку насмешливые объекты-ценности часто считаются плохой практикой (об этом даже говорится в документации Mockito ).

Вместо этого ваш тест должен выглядеть так:

@Test
public void updateCustomer_WithValidInput_ShouldReturnUpdatedInput() {
    String customerId = "customerId";
    String name = "Name";
    String address = "address";
    String language = "language";
    Customer customer = new Customer();
    customer.setName(name);
    customer.setAddress(address);
    customer.setLanguage(language);
    CustomerInputData inputData = new CustomerInputData();
    inputData.setId(customerId);

    doReturn(customer).when(customerService).getCustomerById(customerId);

    CustomerInputData updatedInput = classUnderTest.updateCustomer(inputData);

    assertSame(inputData, updatedInput);
    assertEquals(name, updatedInput.getCustomerName());
    assertEquals(address, updatedInput.getCustomerCity());
    assertEquals(language, updatedInput.getLanguage());
}

Хорошую презентацию по модульному тестированию смотрите в недавней статье Martin Fowler .

2
Rogério