Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .bsl-language-server.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
"runAllTestsArguments": "./src/cli/main.os e --file %s --genericCoverage build/genericCoverage.xml --openTestReport build/otr.xml --cobertura build/cobertura.xml",
"runTestArguments": "./src/cli/main.os e --file %s -m %s --genericCoverage build/genericCoverage.xml --openTestReport build/otr.xml --cobertura build/cobertura.xml",
"debugTestArguments": "./src/cli/main.os e --debug 2801 --file %s -m %s",
"getTestsResultPattern": "^[^.]+\\.([^\\s.]+).*$"
"getTestsResultPattern": "^[^.]+\\.([^\\s.]+).*$",
"getTestsByTestRunner": true
}
},
"inlayHint": {
Expand Down
61 changes: 61 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ OneUnit поддерживает следующие аннотации для н
| `&Тег` | Используется для объявления [тегов для фильтрации](#17-теги) тестов на уровне набора или метода |
| `&Выключен` | Используется для [отключения](#15-отключение-тестов) тестового набора или тестового метода |
| `&Таймаут` | Используется для провала `&Тест`, `&ПараметризованныйТест` или `&ПовторяемыйТест` метода, если его выполнение превышает заданную продолжительность. |
| `&Изолированный` | Выполняет тест или весь набор [в изоляции](#113-изоляция-тестов) - в свежей поделке или в отдельном процессе |

### 1.2 Тестовые методы и наборы

Expand Down Expand Up @@ -565,6 +566,66 @@ OneUnit предоставляет возможность повторять т

> Если таймаут указан для [`&ПовторяемыйТест`](./docs/api/Аннотации/ПовторяемыйТест.md) или [`&ПараметризованныйТест`](./docs/api/Аннотации/ПараметризованныйТест.md), то он будет применён к каждому вызову тестового метода.

### 1.13 Изоляция тестов

Аннотация [`&Изолированный`](./docs/api/Аннотации/Изолированный.md) выполняет тест или весь тестовый набор в изоляции: так, как будто набор прогнали только с этим тестом. Снаружи это обычный тест - его статус, сообщение и вывод попадают в общий план, репортёры и статистика не знают об изоляции.

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

Аннотация вешается на тест или на конструктор `&ТестовыйНабор`. На наборе изолируется весь набор одним контекстом, на тесте - каждый такой тест своим. Изолированный контекст получает полный жизненный цикл набора, включая `&ПередВсеми` и `&ПослеВсех`.

Уровень изоляции задаётся параметром `Уровень`:

* `"Поделка"` (по умолчанию) - тот же процесс, но свежая поделка. Защищает от протечек состояния желудей между тестами;
* `"Процесс"` - отдельный дочерний процесс. Защищает от того, что поделкой не лечится: глобальная система типов, падающие импорты, `ЗавершитьРаботу`.

```bsl
&Тест
&Изолированный
Процедура ТестВСвежейПоделке() Экспорт
```

Падение изолированной среды не роняет общий прогон: набор или тест помечается сломанным с причиной, а прогон продолжается.

Параметр `Импорты` (только для уровня `"Процесс"`) переносит подключение библиотек из шапки файла в изолированный процесс. Импорт подключается в дочернем процессе после старта его поделки - поэтому библиотека, ломающая процесс уже при подключении, не мешает ни родительскому прогону, ни самому дочернему. Пути разрешаются относительно файла набора.

```bsl
&Тест
&Изолированный(Уровень = "Процесс", Импорты = "./ОшибочныеКлассы/ДваЖелудяСОднимИменем")
Процедура ДваЖелудяСОднимИменемКонфликтуют() Экспорт

Попытка
Поделка = Новый Поделка();
Исключение
Ожидаем.Что(ИнформацияОбОшибке().Описание).Содержит("уже существует");
КонецПопытки;

КонецПроцедуры
```

Параметр `Совет` принимает [лямбда-выражение](https://github.com/oscript-library/lambdas) без параметров, возвращающее `СоветДругогоМастера` для создания изолированной поделки. Лямбда выполняется в контексте тестового набора - ей доступны его поля и экспортные методы. Так тесты получают собственную поделку с нужной конфигурацией без ручной сборки:

```bsl
Перем _Поделка;

&ТестовыйНабор
&Изолированный(Совет = "() -> ГенераторДанных.СоветСОднимКоннектором()")
Процедура ПриСозданииОбъекта(&Пластилин Поделка)
_Поделка = Поделка;
КонецПроцедуры

&Тест
Процедура ХранилищеПолучается() Экспорт
Хранилище = _Поделка.НайтиЖелудь("ХранилищеСущностейОсновное");
...
```

Экземпляр изолированного набора создаётся в изолированной поделке, поэтому его конструктор инжектит желуди, сконфигурированные советом, включая саму поделку через `&Пластилин Поделка`.

> Для уровня `"Процесс"` лямбда совета исполняется в дочернем процессе, поэтому значения деталек совета не ограничены сериализуемостью и могут быть объектами. Экземпляр набора для захвата поднимается там напрямую через `Новый`: если конструктор набора требует параметров, лямбда исполняется без захвата - модули, импортированные файлом набора, доступны в любом случае.

Обнаружение тестов (`oneunit discover` и MCP-инструмент `discover_tests`) показывает фактический состав изолированных наборов: состав обнаруживается в изолированной среде без исполнения тестов, поэтому внешний тулинг видит их так же, как обычные наборы.

## 2. Запуск тестов

### 2.1 Запуск тестов из командной строки
Expand Down
49 changes: 49 additions & 0 deletions docs/api/Аннотации/Изолированный.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# АннотацияИзолированный

## ПриСозданииОбъекта

```bsl
// Аннотация выполняет тест или весь тестовый набор в изоляции: так, как будто
// набор прогнали только с этим тестом - в свежей поделке или в отдельном процессе.
// Снаружи это обычный тест: его статус, сообщение и вывод попадают в общий план.
//
// Нужна для тестов, которые иначе отравляют общий прогон: проверяют ошибки
// обнаружения, конфликты желудей, падающие импорты, либо требуют собственной
// поделки с отдельной конфигурацией.
//
// Вешается на тест или на конструктор `&ТестовыйНабор`. На наборе изолируется весь
// набор одним контекстом, на тесте - каждый такой тест своим. При изоляции и набора,
// и теста выигрывает набор.
//
// Параметры:
// Уровень - Строка - Уровень изоляции, см. УровниИзоляции:
// "Поделка" (по умолчанию) - тот же процесс, но свежая поделка;
// "Процесс" - отдельный дочерний процесс.
// Импорты - Строка - Только для уровня "Процесс": пути импортов через запятую,
// подключаемые в изолированном процессе перед файлом набора. Позволяет проверять
// импорты, которые отравляют текущий процесс уже при подключении. На уровне
// "Поделка" запрещены - импорт глобален для процесса и поделкой не изолируется.
// Совет - Строка - [Лямбда-выражение](https://github.com/oscript-library/lambdas)
// без параметров, должно вернуть [СоветДругогоМастера](https://github.com/autumn-library/autumn)
// для создания изолированной поделки. Лямбда захватывает объект тестового набора:
// ей доступны поля объекта и его экспортные методы. На уровне "Процесс" лямбда
// исполняется в дочернем процессе, поэтому значения деталек совета не ограничены
// сериализуемостью; экземпляр набора для захвата поднимается там напрямую
// через Новый - если конструктор набора требует параметров, лямбда исполняется
// без захвата (модули, импортированные файлом набора, доступны в любом случае).
//
// Пример:
// 1.
// // Набор целиком выполняется в свежей поделке, сконфигурированной советом
// &ТестовыйНабор
// &Изолированный(Совет = "() -> ГенераторДанных.СоветСОднимКоннектором()")
// Процедура ПриСозданииОбъекта(&Пластилин Поделка) Экспорт
//
// 2.
// // Тест выполняется в отдельном процессе с ядовитым импортом
// &Тест
// &Изолированный(Уровень = "Процесс", Импорты = "../ОшибочныеКлассы/ДваЖелудяСОднимИменем")
// Процедура ДваЖелудяСОднимИменемКонфликтуют() Экспорт
//
Процедура ПриСозданииОбъекта(Уровень = "Поделка", Импорты = "", Совет = "")
```
1 change: 1 addition & 0 deletions lib.config
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
<class name="АннотацияИсточникНеопределено" file="src/core/Классы/АннотацияИсточникНеопределено.os"/>
<class name="АннотацияИсточникПеречисление" file="src/core/Классы/АннотацияИсточникПеречисление.os"/>
<class name="АннотацияИсточникJSON" file="src/core/Классы/АннотацияИсточникJSON.os"/>
<class name="АннотацияИзолированный" file="src/core/Классы/АннотацияИзолированный.os"/>
<class name="АннотацияОтображаемоеИмя" file="src/core/Классы/АннотацияОтображаемоеИмя.os"/>
<class name="АннотацияПараметризованныйТест" file="src/core/Классы/АннотацияПараметризованныйТест.os"/>
<class name="АннотацияПередВсеми" file="src/core/Классы/АннотацияПередВсеми.os"/>
Expand Down
Loading
Loading