JUnit тестирование / вызов функции несколько раз - PullRequest
0 голосов
/ 08 января 2020

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

public String text() {                               
    if (text.isPresent()) {                          
        return text.get();                           
    }                                                
    this.text = Optional.of(extractText(pdDocument));
    return text.get();                               
}

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

Вот пример, когда text () вызывается дважды

private Optional<String> packingListNet() {           
    return locatePattern(text(), PACKING_LIST_NET);   
}  

private Optional<String> packingListNumber() {        
    return locatePattern(text(), PACKING_LIST_NUMBER);
}                  

Буду благодарен за любую информацию, спасибо

Ответы [ 5 ]

2 голосов
/ 08 января 2020

Технический ответ: вы можете использовать библиотеку-насмешку, такую ​​как PowerMockito, для создания смоделированных экземпляров класса Optional. И когда у вас есть фиктивный объект, вы можете указать ему, как реагировать на вызовы методов. Затем вам нужно «вставить» макетируемый необязательный объект в тестируемый класс.

Вы можете использовать это для покрытия первого оператора if: вы ожидаете, что макет увидит вызов isPresent() и вернет true, и затем вернуть указанную c строку. Ваш тестовый сценарий может затем проверить, «вернулась ли ожидаемая строка». То же самое и в обратном случае, когда надруганный необязательный «пустой», вы гарантируете, что возвращается другая строка, и проверяете это.

Но, честно говоря, сомнительно, что вы должны сделать все это.

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

И это будет означать:

  • Включите себя, что вы можете передать (реальный) необязательный объект в тестируемый класс
  • Когда ваш необязательный объект не пустой, ваш тест ожидает ... что вы положили в него
  • Когда ваш необязательный пустой , ваш тест ожидает, что extractText() вернет

Конечно, здесь насмешка действительно проблематична c: необязательный класс final . Поэтому вам нужно либо использовать Mockito с «экспериментальной поддержкой окончательного включения», либо использовать PowerMock (ito) (который я настоятельно советую никогда не использовать).

Итак, как уже было сказано: избегайте насмешек.

2 голосов
/ 08 января 2020

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

Лучшим подходом будет передача всей необходимой информации в качестве параметров метода. Таким образом, они являются поточно-ориентированными;

public static String getText(String textToSearchFor, Document pdfDocument) {
    // extract here
}

Вот как я мог бы написать тест JUnit для такого метода:

public class TextMethodOwnerTest {

    @Test
    public void testGetText_Success() {
        // setup
        String expected = "text to find";
        Document pdf; // Have to get this.
        // exercise
        String actual = TextMethodOwner.getText(expected, pdf);
        // assert
       Assert.assertEquals(expected, actual);
    }

    @Test
    public void testGetText_PackingListNumber() {
        // Add another case here
    }

    @Test
    public void testGetText_PackingListNet() {
        // Add another case here
    }
}
0 голосов
/ 08 января 2020

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

У него есть основной метод, который вызывает метод packingList*() 100 раз для разных потоков, но вы увидите, что часть извлечения вводится только один раз в начале. Для этого я добавил блокировку и использовал блок synchronized. Я понимаю, что это основа c, но подумал, что могу поделиться, поскольку это может помочь другим.

Обратите внимание на изменения в методе public String text().

public class ReusedText{
private static final long PACKING_LIST_NET = 200;
private static final long PACKING_LIST_NUMBER = 120;

private Optional<String> text = Optional.ofNullable( null );
private Document pdDocument;

private static final Object LOCK = new Object();
private static final ExecutorService svc = Executors.newFixedThreadPool( 2 ); 

public ReusedText(Document pdDocument) {
    super();
    this.pdDocument = pdDocument;
}

public static void main( String[] args ){
    ReusedText rt = new ReusedText( new Document( "/path/to/document/on/disk" ) );

    for( int i = 0; i < 100; i++ ) {
        svc.submit( () -> System.out.println( rt.packingListNet() ) );
        svc.submit( () -> System.out.println( rt.packingListNumber() ) );
    }

    svc.shutdown();
}

public String text() {
    if (text.isPresent()) {                          
        return text.get();                           
    }
    else {
        synchronized (LOCK) {
            /* This repeated 'if' block is necessary because 'text' may have got populated while this thread was waiting for lock. */
            if (text.isPresent()) return text.get();  
            else{ 
                System.out.println( "Extracting text..." );
                this.text = Optional.of( extractText( pdDocument ) );
                return text.get();
            }
        }
    }
}

private String extractText( Document doc ) {
    //Read the file contents using some API like java.nio.file.Files or Apache Tika
    return "file contents here!";
}

private Optional<String> packingListNet() {           
    return locatePattern(text(), PACKING_LIST_NET);   
}  

private Optional<String> packingListNumber() {        
    return locatePattern(text(), PACKING_LIST_NUMBER);
}

private Optional<String> locatePattern( String text, long packingListNumber ){
    //Implement your logic with the text here.
    return Optional.of( String.valueOf( packingListNumber ) );
}

private static class Document{
    private String pathToText;

    public Document(String pathToText) {
        super();
        this.pathToText = pathToText;
    }

    public String getPathToText(){
        return pathToText;
    }
}
}
0 голосов
/ 08 января 2020

Вот некоторый псевдокод, как вы могли бы его достичь:

public Class {
   int counter = 0;
   void test() {
      counter++;
   }
}

public ClassTest {

public Class class;

void shouldBeCalledOneTime() {
   class.test();
   AssertThat(class).hasFieldWithValue("counter", 1);
}
}
0 голосов
/ 08 января 2020

Я не уверен, что вы пытаетесь спросить. Информация не ясна, но, возможно, это поможет вам:

Junit и mockito в основном используются вместе. Если вы хотите проверить, что любая функция вызывается только один раз, мы используем метод verify () mockito с параметром atLeast (1)

Например: пример взят из (https://www.baeldung.com/mockito-verify)

List<String> mockedList = mock(MyList.class);
mockedList.clear();
mockedList.clear();
mockedList.clear();
verify(mockedList, atLeast(1)).clear();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...