как написать тестовый пример junit для метода с логикой повтора

Метод повтора точно просматривает папку для определенного файла и возвращает файл, если он присутствует. Он имеет максимальное количество повторных попыток, равное 3, и спит в течение 1 минуты между двумя повторными попытками. Если после максимального количества повторных попыток файл отсутствует, он выдает некоторое исключение.

метод примерно такой

File getFile(int retryCount){
    File file;
    file =getFilefromLocation();
    if(file!=null) return file
    if(file==null and retryCount>0)
    Thread.sleep(1)
     --retryCount;
    File filePicked =getFile( retryCount)
   }
else return null;
}

person user8618585    schedule 28.07.2018    source источник
comment
Возможности могут различаться в зависимости от вашего фактического кода. Можете ли вы опубликовать код, который вы тестируете?   -  person ernest_k    schedule 28.07.2018
comment
Вы очень сильно начинаете с настройки времени задержки. Таким образом, вы можете спать 1 секунду вместо 1 минуты в своем тесте.   -  person GhostCat    schedule 28.07.2018


Ответы (3)


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

person Henry    schedule 28.07.2018
comment
Я буду только издеваться над файлом и сделать файл доступным, скажем, через 1 или 2 минуты, и подтвердить его присутствие или подтвердить отсутствие доступности, но я не могу контролировать, сколько раз фактический метод повторялся. Что я хочу знать, так это как знать, сколько раз метод повторял попытку. - person user8618585; 28.07.2018
comment
Вы увидите количество попыток, сделанных в издевательском объекте. - person Henry; 28.07.2018

Я бы сделал время повтора настраиваемым и сделал его 1 секунду для тестирования. У вас могут быть тесты, в которых файл уже есть, никогда не бывает, и один, в котором он добавляется в качестве фонового потока. Должно пройти около 5 секунд.

Я бы также рассматривал более короткое время повторных попыток, например, 120 попыток каждую 1 секунду вместо 3 раз в минуту.

person Peter Lawrey    schedule 28.07.2018

Я постараюсь дать несколько советов.

1) Здесь я бы не стал издеваться над всей логикой проверки наличия файла, поскольку она является частью поведения тестируемого метода. то есть, когда вы вызываете getFilefromLocation().

2) Использовать короткую задержку между повторными попытками — это идея, но достаточно ли этого, чтобы сделать ваш тест надежным?
Не совсем потому, что вы также должны утверждать, что Thread.sleep() был вызван и с ожидаемым значением. Отсутствие проверки в модульном тесте означает, что любой может удалить Thread.sleep() в методе getFile(), и тест все равно пройдет. Вы действительно не хотите этого.
Обратите внимание, что вы не можете легко издеваться над этим: это static. Вам следует переместить это утверждение в DelayService, над которым вы могли бы издеваться.

3) На самом деле вы параметризуете retryCount. Когда вы пишете модульные тесты, вы хотите проверить поведение компонентов в соответствии с вашими требованиями. Таким образом, вы также должны убедиться, что класс, который зависит от getFile(int retryCount), эффективно передает ожидаемый параметр: 3.
Кроме того, если вы не хотите разрешать более определенного числа повторных попыток, вам также нужно добавить эту проверку в метод и утвердите это правило в модульном тесте.

В соответствии с двумя первыми пунктами ваш фактический код может быть реорганизован как:

private FileLocator fileLocator; // added dependency
private DelayService delayService; // added dependency

//  constructor to set these dependencies
public MyService(FileLocator fileLocator, DelayService delayService){
    ...
}

File getFile(int retryCount){
    File file;
    file = fileLocator.getFilefromLocation(); // -> change here
    if(file!=null) return file
    if(file==null and retryCount>0){
       delayService.waitFor(); // -> other change here
       --retryCount;
       File filePicked = getFile(retryCount)
    }
    else return null;
}

Что касается части модульного теста, вы можете использовать Mockito для имитации и смешивания «простых» модульных тестов с параметризованными тестами, поскольку некоторые сценарии имеют аналогичное поведение с разницей в количестве фактических повторных попыток.
Например, повторные попытки 0, 1, 2 и 3 раза и поиск файла — это 4 случая, которые вы можете параметризовать.
И, наоборот, неспособность найти файл не требует параметризации, поскольку все повторные попытки должны выполняться для проверки поведения.

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

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.junit.jupiter.api.Assertions;
import org.mockito.Mockito;
import org.mockito.Mock;

private static final long EXPECTED_DELAY_MN = 1; 
private static final long RETRY_COUNT = 3; 

@Mock
FileLocator fileLocatorMock;

@Mock
private DelayService delayServiceMock;


MyServiceTest myServiceTest;

public MyServiceTest(){
   myServiceTest = new MyServiceTest(fileLocatorMock, delayServiceMock);
}

@ParameterizedTest
@ValueSource(ints = { 0, 1, 2, 3 })
public void getFileThatFailsMultipleTimeAndSuccess(int nbRetryRequired){    

    // failing find
    for (int i=0; i < nbRetryRequired; i++) {
        Mockito.when(fileLocatorMock.getFilefromLocation(...)).thenReturn(null);
    }

    // successful find
    File fileByMock = new File(...); //fake file
    Mockito.when(fileLocatorMock.getFilefromLocation(...)).thenReturn(fileByock);
    File actualFile = myServiceTest.getFile(RETRY_COUNT);

    // assertions
    Mockito.verify(delayServiceMock, Mockito.times(nbRetryRequired)) 
           .waitFor();
    Assert.assertSame(fileByMock, actualFile);

   }
}
person davidxxx    schedule 28.07.2018