В этом мысленном эксперименте мы используем Tribuo в пользовательском расширении JUnit, чтобы увидеть возможность использования машинного обучения (ML) для потенциального получения полезных сведений о гарантии качества (QA) для данной услуги или продукта.

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

Tribuo — это библиотека Java для машинного обучения с открытым исходным кодом, которая предоставляет инструменты для классификации, регрессии, кластеризации и т. д.

Для целей этого поста я предполагаю, что читатели знакомы с моделью расширения JUnit. Если вам интересно узнать больше о модели расширения JUnit и о том, как создать собственное расширение, вы можете обратиться к моей статье на InfoQ. Кроме того, я также предполагаю, что читатель знаком с концепциями машинного обучения.

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

public class HashUtilsTest {
  @Test
  public void validHashTest() {
    var valueToHash = "JUnit with Tribuo is fun";
    var actualHash = HashUtils.hash(valueToHash);
    ...
    assertEquals(expectedHash, actualHash);
  }
}

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

Мы можем создать пользовательское расширение JUnit, которое вычисляет общее время, затраченное на выполнение тестового класса, и запустить модель машинного обучения Tribuo для обнаружения аномалий, чтобы найти любые аномалии во время выполнения теста. Для этого расширение записывает временные данные в CSV-файл. И для простоты все записываемые данные наивно интерпретируются как EXPECTED наблюдение. Для этого можно использовать встроенные файловые методы Java:

var csvPath = ...
var time = ...
Files.writeString(
    csvPath,
    time + ",EXPECTED\n",
    StandardCharsets.UTF_8,
    StandardOpenOption.APPEND
);

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

var oneClass = new SVMAnomalyType(SVMAnomalyType.SVMMode.ONE_CLASS); 
var params = new SVMParameters<>(oneClass, KernelType.RBF);
params.setGamma(MODEL_GAMMA);
params.setNu(MODEL_NU);
var trainer = new LibSVMAnomalyTrainer(params);
var model = trainer.train(trainingDataset);
var newRow = Map.of(
    "name", clazz.getName(),
    "duration", String.valueOf(durationInSec)
);
var headers = java.util.List.copyOf(newRow.keySet());
var row = new ColumnarIterator.Row(trainingDataset.size(), headers, newRow);
var example = sRowProcessor.generateExample(row,false).get();
prediction = model.predict(example);
// This is where you would generate an actual report.
System.out.println(example);
System.out.println(prediction);

Все, что нам нужно сделать, это использовать это новое расширение в нашем тестовом классе, как показано ниже:

@AnomalyDetector
public class HashUtilsTest {
  @Test
  public void validHashTest() {
    ...
    assertEquals(expectedHash, actualHash);
  }
}

Предположим, что в приведенном выше примере успешное выполнение тестов обычно занимает от 0,5 до 1 секунды. Однако после изменения хэш-функции теперь успешное выполнение тестов занимает 3 секунды. Это может указывать на потенциальную регрессию производительности (разумеется, чрезмерное упрощение). Если обученная модель правильно выполняет свою работу, это необычное поведение должно быть помечено как проблема.

Когда время запуска тестового класса соответствует ожидаемому, мы видим что-то вроде этого из прогноза модели:

Prediction(maxLabel=(EXPECTED,...

Когда модель обнаруживает аномалию, мы видим что-то вроде этого:

Prediction(maxLabel=(ANOMALOUS,...

Это только начало. Могут быть более полезные приложения использования машинного обучения в среде тестирования для автоматического анализа тестов и обеспечения более качественного контроля качества. Благодаря отличным библиотекам с открытым исходным кодом, таким как JUnit и Tribuo, мы можем легко исследовать такие варианты использования!

Вы можете проверить экспериментальный код на GitHub.

Присоединиться к разговору!

Если вам интересно, что происходит с разработчиками Oracle в их естественной среде обитания, присоединяйтесь к нам на нашем общедоступном канале Slack! Мы не против быть вашим аквариумом 🐠