Как написать некапсулированные модульные тесты? - PullRequest
1 голос
/ 05 апреля 2019

У меня есть переменная с автоматическим подключением

@Autowired
private DocumentConfig documentConfig;

Я хочу сделать тесты для DocumentService с различными состояниями этого объекта конфигурации.Какие у меня варианты?Какой вариант лучше?

Первая идея такова:

@Test
public void save_failure() {
    documentConfig.setNameRequired(true);
    /*
    testing code goes here
    */
    documentConfig.setNameRequired(false);
}

Но я хочу быть несколько увереннее, что переменная сбрасывается после теста, чтобы не мешать другим тестам, чтобы убедиться, что только этот тест выдает ошибку, если он является источником проблемы.

Моя новая идея заключалась в следующем:

@Before
public void after() { documentConfig.setNameRequired(true); }
@Test
public void save_failure() {
    /*
    testing code goes here
    */
}
@After
public void after() { documentConfig.setNameRequired(false); }

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

Сейчас я остановился на компромиссе:

@Test
public void save_failure() {
    documentConfig.setNameRequired(true);
    /*
    testing code goes here
    */
}
@After
public void after() { documentConfig.setNameRequired(false); }

Кажется, он выполняет все, что я хочу, но у меня есть нескольковопросы.
Если предположить, что nameRequired начинается со значения false, это гарантированно не мешает другим тестам?
Можно ли как-нибудь прояснить это?И для себя будущего, и для других.

Ответы [ 3 ]

2 голосов
/ 05 апреля 2019

Вы можете создать его перед каждым тестом.Что-то вроде

private DocumentConfig documentConfig;

@Before
public void createConfig() {
    documentConfig = new DocumentConfig(mockedParams);
}
1 голос
/ 08 апреля 2019

Часто используемый подход состоит в том, чтобы установить фиктивную DocumentConfig и внедрить ее в метод setUp() (аннотированный @Before), чтобы весь контекст сбрасывался в каждом тесте, например:

@Before
public void setUp() {
    this.documentConfig = new DocumentConfig();
    this.documentConfig.setNameRequired(false);
    this.service = new DocumentService(this.documentConfig);
}

В этом случае я настроил простой объект с nameRequired, равным false. Я мог бы, вероятно, удалить этот оператор, потому что поле boolean по умолчанию равно false.

Если вы не используете инжекцию конструктора и у вас нет установщика для documentConfig, вам придется использовать отражение, чтобы ввести поле, например:

ReflectionTestUtils.setField(this.service, "documentConfig", this.documentConfig);

В вашем тесте вы можете написать что-то вроде этого:

@Test
public void save_failure() {
    this.documentConfig.setNameRequired(true);
    // TODO: Implement test
}

В качестве альтернативы, вы можете издеваться над DocumentConfig, чтобы вы не полагались на его реализацию для тестирования DocumentService. Я предполагаю, что вы звоните isNameRequired() где-то в коде DocumentService, так что вы можете посмеяться над этим так:

@Before
public void setUp() {
    // Use a static import for Mockito.mock()
    this.documentConfig = mock(DocumentConfig.class);
    this.service = new DocumentService(this.documentConfig);
}

@Test
public void save_failure()  {
    // Use a static import for Mockito.when()
    when(this.documentConfig.isNameRequired()).thenReturn(true); 
    // TODO: Implement test
}

Так как эта установка для насмешек / инъекций происходит довольно часто, у Mockito также есть собственный бегун, который позволяет избавиться от метода setUp(), например:

@RunWith(MockitoJUnitRunner.class)
public class DocumentServiceTest {
    @InjectMocks
    private DocumentService documentService;
    @Mock
    private DocumentConfig documentConfig;

    @Test
    public void save_failure()  {
        when(this.documentConfig.isNameRequired()).thenReturn(true); 
        // TODO: Implement test
    }
}
1 голос
/ 05 апреля 2019

Пока не ясно, какую платформу тестирования вы используете. Для простых модульных тестов сделайте значение доступным для инъекции с помощью инженера сеттера или конструктора. Что бы ни подходило для вашей конкретной ситуации.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...