Тестовый набор Junit для частного метода - PullRequest
0 голосов
/ 13 февраля 2020

У меня есть класс ниже. Я новичок в написании тестов Junit. Мне нужно написать контрольный пример для этого. Как мне написать тестовый метод для startSchemaMaintenance метода в тестовом классе, так как он вызывает закрытый метод без аргументов?

public class SchemaMaintenance {

    //Loading statuses overview
    // NOT_STARTED = 0
    // START_LOADING = 1
    // IN_PROGRESS = 2
    // COMPLETED = 3
    // LOADING_ERROR = 4
    private static volatile Integer loading_status = 0;

    public void startSchemaMaintenance() throws Exception {
        if (checkLoadingStatus() == 1) {
            doSchemaMaintenance();

            loading_status = 3;
        }
    }

    private void doSchemaMaintenance(){
        //Do something....
    }

    private int checkLoadingStatus() throws Exception {
        if (loading_status==0 ||loading_status == 2) {
            synchronized (loading_status) {
                if (loading_status==0) {
                    loading_status = 2;
                    return 1;
                }else if(loading_status == 2) {
                    while(loading_status == 2);

                    if((loading_status == 4)){

                        throw new Exception("status = " + 4);
                    }
                }else if(loading_status == 4) {

                    //log.error(generateErrorMessage());
                    throw new Exception("status = " + 4);
                }
            }
        }else if((loading_status == 4)){
            //log.error(generateErrorMessage());
            throw new Exception("status = " + 4 );
        }

        return loading_status;

    }
}

Ответы [ 3 ]

2 голосов
/ 13 февраля 2020

Прежде всего пара вещей:

  1. Почему loading_status stati c? В основном 2 экземпляра этого класса будут использовать одну и ту же переменную loading_status. loading_status либо не должен быть stati c, либо checkLoadingStatus также должен быть stati c.
  2. loading_status ужасно назван. Если вы хотите сохранить это значение c, вам следует назвать это LOADING_STATUS. Если это не будет stati c, назовем его loadingStatus. Это соглашение Java.
  3. Вы должны создать правильный тип перечисления для loading_status, а не целое число.
  4. while (loading_status == IN_PROGRESS); - просто плохая практика. По крайней мере, вы можете сделать следующее: while(loading_status == IN_PROGRESS) { Thread.sleep(100); }; Однако лучше использовать тайм-аут. Что-то вроде:
long timeoutMillis = 5000L; // Should come from a configuration or something
long endTimeMillis = System.currentTimeMillis() + timeoutMillis;
while (loadingStatus == IN_PROGRESS) {
    long remainingMillis = end - System.currentTimeMillis();
    if (remaining <= 0) {
        // Timeout while loading
        loadingStatus = LOADING_ERROR;
        break;
    }
    Thread.sleep(50);
}
// ...

И, наконец, я предполагаю, что что-то обновит loadingStatus до завершения или что-то еще. Я полагаю, вы используете синхронизированный там же. Если загрузка происходит в 2 разных потоках, вы окажетесь в тупике. Если checkLoadingStatus сначала вводит синхронизированный блок, поэтому, когда загрузка завершена, поток загрузки никогда не сможет войти в синхронизированный блок, потому что checkLoadingStatus удерживает блокировку.

Последний, но не менее важный, чтобы ответить на ваш вопрос, если вы хотите сохранить свой метод закрытым, вы можете вызвать его через рефлексию, но это опять-таки плохая практика. Как правило, вам следует избегать модульного тестирования частных методов и модульного тестирования тех методов, которые его вызывают. Однако, если вам определенно необходимо выполнить модульное тестирование определенного метода, сделайте его закрытым для пакета, а не закрытым, а затем вы можете создать модульный тест в том же пакете, где находится класс, содержащий ваш метод. И вы можете добавить комментарий к методу, говоря, что он виден только для модульного тестирования. Пример структуры вашего кода в этом случае:

src
+-- main
+-- +-- com/app/MyClass.java
+-- test
    +-- com/app/MyClassTest.java // this test class will able to access package-private methods in MyClass
0 голосов
/ 13 февраля 2020

Ваш приватный метод работает в соответствии со значением внутренней приватной переменной loading_status , поэтому в ваших тестах вы сможете просто изменить эту переменную. Для этого вы можете сделать следующее:

package com.test

import com.test.SchemaMaintenance;
import org.junit.Test;
import org.mockito.internal.util.reflection.Whitebox;

public class SchemaMaintenanceTest {

    @Test
    public void TestSchema() throws Exception {
        SchemaMaintenance schema = new SchemaMaintenance();
        Whitebox.setInternalState(schema,"loading_status",2);
        schema.startSchemaMaintenance();
    }

}

Предположим, вы должны включить в свой проект зависимость mockito :

например, Maven

<dependency>
  <groupId>org.powermock</groupId>
  <artifactId>powermock-api-mockito</artifactId>
  <version>1.6.4</version>
</dependency>
0 голосов
/ 13 февраля 2020

Обычно, когда вы не можете протестировать свой код, вы должны подумать о его переписывании, чтобы он был тестируемым. Закрытые методы нельзя вызывать обычным образом, вне вашего класса, даже в рамках теста JUnit.

Есть несколько вещей, которые вы можете сделать, чтобы сделать его тестируемым:

  1. Перепишите ваш код, чтобы разделить метод на более мелкие. Всегда следует делать, где это уместно.

  2. Вы можете сделать пакет методов закрытым (удалить модификатор private), чтобы ваш тестовый класс, который должен находиться в том же пакете, мог получить доступ it.

  3. Вы можете сделать метод защищенным, чтобы вы могли наследовать свой класс в своем тесте и косвенно вызывать этот метод над своим унаследованным классом.

  4. Вы можете вызвать метод, который вызывает метод, который вы хотите протестировать и сделать свои утверждения соответственно.

Если вы склонны изменить видимость метода для упаковки приватного или защищенного, вы может аннотировать ваш метод как @VisibleForTesting, поэтому такие инструменты, как Sonar и другие члены команды, знают, почему он не является частным.

Надеюсь, это поможет.

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