Как смоделировать UUID.randomUUID () из пакета java.util? - PullRequest
0 голосов
/ 06 сентября 2018

Что не так с UUID.randomUUID() - его просто нельзя высмеять

Можно ли издеваться? Или у меня есть ошибка в моем источнике?

Посмотрите на пример:

1) Класс, который тестируется

package com.grayen;

import java.util.UUID;

public class TestedClass {
    public UUID getUuid() {
        return UUID.randomUUID();
    }
    public UUID getUuidFromWrapper() {
        return UuidWrapper.randomUUID();
    }
}

Один метод использует обертку для UUID, и я могу высмеять эту обертку!

2) Обертка для реального UUID (все модификаторы одинаковы)

package com.grayen;

import java.util.UUID;

public final class UuidWrapper {
    public static UUID randomUUID() {
        return UUID.randomUUID();
    }
}

3) Тестирование (последняя закомментированная строка вызывает исключение)

package com.grayen;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import java.util.UUID;
import static org.junit.Assert.assertEquals;

@PrepareForTest({UUID.class, UuidWrapper.class})
@RunWith(PowerMockRunner.class)
public class TestedClassTest {

    @Test
    public void testMethod() {
        UUID uuid = UUID.randomUUID();

        PowerMockito.mockStatic(UUID.class);
        PowerMockito.mockStatic(UuidWrapper.class);

        PowerMockito.when(UUID.randomUUID()).thenReturn(uuid);
        PowerMockito.when(UuidWrapper.randomUUID()).thenReturn(uuid);

        TestedClass testedClass = new TestedClass();

        assertEquals(uuid, testedClass.getUuidFromWrapper());
        //assertEquals(uuid, testedClass.getUuid());
    }
}

Ответы [ 2 ]

0 голосов
/ 06 сентября 2018

Итак, я взял твой код и заставил его работать. Все, что вам нужно сделать, это добавить TestedClass.class к вашему @PrepareForTest.

package com.grayen;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import java.util.UUID;
import static org.junit.Assert.assertEquals;

@PrepareForTest({
    UUID.class, 
    UuidWrapper.class, 
    TestedClass.class
})
@RunWith(PowerMockRunner.class)
public class TestedClassTest {

    @Test
    public void testMethod() {
        UUID uuid = UUID.randomUUID();

        PowerMockito.mockStatic(UUID.class);
        PowerMockito.mockStatic(UuidWrapper.class);

        PowerMockito.when(UUID.randomUUID()).thenReturn(uuid);
        PowerMockito.when(UuidWrapper.randomUUID()).thenReturn(uuid);

        TestedClass testedClass = new TestedClass();

        assertEquals(uuid, testedClass.getUuidFromWrapper());
        assertEquals(uuid, testedClass.getUuid());
    }
}

Редактировать

Я не видел комментарий, но k5_ указал на него.

0 голосов
/ 06 сентября 2018

Насмешка над статическим методом - это всегда хрупкий подход. Если возможно, предпочтите использовать нестатический источник UUID, который затем можно легко смоделировать.

Например:

/**
 * A source of new {@link UUID} instances.
 */
public interface UuidSource {
    /**
     * Returns a new {@link UuidSource} that generates UUIDs using {@link UUID#randomUUID}.
     */
    public static UuidSource random() {
        return UUID::randomUUID;
    }

    /**
     * Returns a new {@link UUID} instance.
     *
     * <p>The returned value is guaranteed to be unique.
     */
    UUID newUuid();
}

Затем вы можете добавить его в TestedClass или иметь TestedClass частного участника:

public class TestedClass {
    private UuidSource uuidSource = UuidSource.random();

    public UUID getUUID() {
        return uuidSource.newUuid();
    }
    // etc.
}

Затем, чтобы протестировать его, вы можете либо иметь конструктор только для тестирования, чтобы разрешить инъекцию в фиктивном UuidSource, либо вы можете напрямую заменить значение поля uuidSource (либо расширив его видимость, либо используя отражение или что-то).

В качестве бонуса: это отделяет ваш фактический производственный код от UUID.randomUUID(). Если позже вы решите, что вам нужно использовать UUID версии 2 (на основе datetime) или какую-то другую версию, а не случайные UUID, вы также можете легко изменить это в своем рабочем коде. Это то, что люди имеют в виду, когда говорят, что, делая ваш код более тестируемым, обычно улучшается общий дизайн.

...