Ниже приведен пример тестового сценария для сквозного тестирования «Редактора наборов» с тестами для создания набора, удаления одного и удаления всех наборов:
describe('Редактор наборов', () => {
beforeEach(() => {
return cy.login();
});
it('Создание набора modbus', function() {
cy.visit('/sedmax/web/ui/sets_data_server/editor/index')
.wait(1000)
.getByText(/Создать набор/i)
.click({ force: true })
.wait(500)
.get('.ant-modal-content .ant-btn-primary')
.click();
});
it('Удаляем набор modbus', function() {
cy.visit('/sedmax/web/ui/sets_data_server/editor/index')
.wait(1000)
.get('.ant-table-row.ant-table-row-level-0 td')
.first()
.click()
.getByText(/Удалить выбранное/i)
.click({ force: true })
.get('.ant-modal-confirm-btns button.ant-btn.ant-btn-primary')
.click()
.wait(1000);
});
it('Удалить все наборы modbus', function() {
cy.request('POST', '/sedmax/configuration/data_server_set/create', {
protocolID: 2
});
cy.request('POST', '/sedmax/configuration/data_server_set/create', {
protocolID: 2
});
cy.visit('/sedmax/web/ui/sets_data_server/editor/index')
.wait(1000)
.get('thead.ant-table-thead input[type=checkbox]')
.click()
.getByText(/Удалить выбранное/i)
.click({ force: true })
.get('.ant-modal-confirm-btns button.ant-btn.ant-btn-primary')
.click()
.wait(1000);
});
});
Так же были написаны сквозные тесты для изменения настроек в наборах Modbus и МЭК-104.
Для Unit-тестирования использован фреймворк Jest - лидер тестовых библиотек, так как:
- умеет распараллеливать тестирование для ускорения процесса
- позволяет оценить покрытие кода
- имеет возможность имитировать любые объекты за пределами области действия теста (в виде тестовых данных)
- умеет анализировать типы появляющихся ошибок.
Пример модульного теста для проверки создания компонента модального окна «Создание набора» и его функционала приведен ниже:
import React from 'react';
import ModalCreateSetConnect, { ModalCreateSet } from '../ModalCreateSet';
import {
renderWithIntlAndRedux,
cleanup,
render,
intl
} from '../../../../tests/setupTests';
import { mockProtocols } from '../../../../tests/__mock__/classifiers.mock';
describe('ModalCreateSet', () => {
afterEach(cleanup);
it('should render a ModalCreateSet, visibility', () => {
// Arrange
const createSet = jest.fn();
const changeStateModalCreateSet = jest.fn();
const { container, getByText } = render(
<ModalCreateSet
set={{ id: 1, created: undefined }}
intl={intl}
isFetching={false}
modalState
protocols={[mockProtocols]}
createSet={createSet}
changeStateModalCreateSet={changeStateModalCreateSet}
/>
);
// Act
const submitButton = getByText('OK');
const cancelButton = getByText('Cancel');
submitButton.click();
cancelButton.click();
// Assert
expect(createSet).toHaveBeenCalledTimes(1);
expect(changeStateModalCreateSet).toHaveBeenCalledTimes(1);
expect(container).toMatchSnapshot();
});
it('should render a ModalCreateSet', () => {
const { container } = renderWithIntlAndRedux(<ModalCreateSetConnect />);
expect(container).toMatchSnapshot();
});
});
Где, mockProtocols это тестовые данные:
export const mockProtocols = {
id: 2,
code: '',
name: 'Modbus TCP',
state: 0
};
На рисунке 3.2 представлен процесс подготовки внесенных изменений к внедрению на тестовый сервер, но что-то пошло не так и была обнаружена ошибка на этапе Unit-тестирования.
Рисунок 3.2 - обнаружена ошибка при автоматическом тестировании.
3.2 Внедрение
Вся система обслуживается специальным сервисом GitLab. Это сайт и система управления проектами с возможностью ведения документации и системой отслеживания ошибок.
Разработчики используют распределенную систему контроля версий Git и с помощью нее они изменяют модули системы и заливают на сервер GitLab.
При этом когда изменения заливаются на сервер, происходит отработка тестов, сборка бандлов (организация и компилирование множества ресурсов и библиотек, необходимых для современного веб-проекта в минимизированный файл), и экспортирование на сервер и в зависимые репозитории.
На рисунке 3.3 представлено успешное выполнение всех этапов обновления модуля «Редактор наборов». В результате все изменения были перенесены на тестовый сервер.
Рисунок 3.3 - тесты, сборка бандла и обновление сервера успешно выполнены
После этапа тестирования на серверах SEDMAX, новые модули отправляются на тестирование к заказчику.
4. РАЗРАБОТКА МЕТОДИЧЕСКИХ УКАЗАНИЙ ПО РАБОТЕ С СИСТЕМОЙ
4.1 Виджеты
Для создания новых виджетов в правой части главного меню есть кнопка в виде глаза. При нажатии правой кнопкой мыши открывается контекстное меню со списком уже имеющихся виджетов, в котором нужно нажать «Добавить виджет». Меню представлено на рисунке 4.1.
Рисунок 4.1 - меню виджетов.
Откроется модальное окно создания нового виджета. Нужно ввести название нового виджета. Слева в дереве нужно выбрать устройства. Параметры выбранных устройств окажутся в таблице «Доступные параметры». В данной таблице доступен поиск по устройствам и тегам.
После выбора доступных параметров нужно нажать на кнопку «Переместить выбранное». В результате выбранные параметры окажутся в таблице «Выбранные параметры». В этой таблице можно воспользоваться поиском по всем полям таблицы и ввести псевдонимы для параметров.
После всех проделанных шагов нужно нажать на кнопку «Создать». Модальное окно представлено на рисунке 4.2.
Рисунок 4.2 - модальное окно создания нового виджета.
Теперь, вызвав контекстное меню, нажав на иконку глаза можно увидеть список всех виджетов, включить/отключить отображение конкретного виджета.
В списке виджетов можно удалить виджет или его редактировать при нажатии на соответствующие иконки.
При нажатии на иконку глаза левой кнопкой мыши можно включить и отключить глобальную видимость всех виджетов.
Созданные виджеты можно перетаскивать по всему экрану. Их параметры, позиции и видимость сохраняются для конкретного пользователя.
4.2 Паспорт и диспетчерские метки на мнемосхемах
Открытие паспорта и диспетчерских меток можно произвести по нажатию на элемент мнемосхемы правой кнопкой мыши. В результате откроется контекстное меню, в котором нужно выбрать соответствующие пункты.
В паспорте объекта есть информация о его параметрах. В таблице, в соответствующем поле можно отправить команду ручного ввода или сбросить его.
Паспорт представлен на рисунке 4.3.
Рисунок 4.3 - паспорт объекта в модуле мнемосхем
В окне диспетчерских меток можно установить или снять соответствующие метки и оставить комментарий к действию. На рисунке 4.4 представлено окно диспетчерских меток.
Рисунок 4.4 - паспорт и диспетчерские метки в мнемосхемах
4.3 Редактор наборов
Редактор наборов представляет таблица наборов, которые можно редактировать и удалять. Для создания нового набора нужно нажать на соответствующую кнопку в редакторе наборов. Появится модальное окно с выбором протокола для набора: Modbus или МЭК-104.
Модальное окно представлено на рисунке 4.5.
Рисунок 4.5 - модальное окно для выбора протокола для набора
На рисунке 4.6 представлен список наборов.
Рисунок 4.6 - список наборов
После создания набора, пользователь попадает в настройки созданного набора, где нужно выбрать устройства из дерева, выбрать параметры нужных устройств из «доступных параметров» и добавить их в «параметры набора», а также заполнить главные поля набора и дополнительные поля параметров набора. На рисунке 4.7 представлена «настройка набора».
Рисунок 4.7 - настройка набора
На рисунке 4.8 представлено модальное окно расширенных настроек для протокола МЭК-104.
Рисунок 4.8 - настройка набора
4.4 Анализ полноты данных
Для того чтобы воспользоваться нужным инструментом, нужно выбрать тип отчета: «часы в датах» или «даты в месяцах», далее устройство из дерева устройств и нужные даты в выпадающем календаре.
На рисунке 4.9 представлен календарь для выбора диапазона дат.
Рисунок 4.9 - выпадающий календарь для выбора нужных дат
При наведении курсора на конкретную ячейку диаграммы, появляется подсказка с датой и соответствующим ей значением.
Рисунок 4.10 - выпадающий календарь для выбора нужных дат
Все модули задокументированы и протестированы с помощью GitLab.
ЗАКЛЮЧЕНИЕ
Во ходе выполнения выпускной квалификационной работы был реализован функционал новых модулей и доработаны старые
Разработка на базе ReactJS, Redux, Golang, MongoDB позволила обеспечить:
- высокую надежность модулей;
- стабильность высоконагруженных модулей
- реализацию требуемого функционала;
- быструю скорость взаимодействия пользователя с приложением;
- читаемость кода.
В будущем планируется добавить поддержку новых протоколов для редактора наборов, переписать модуль «виджеты» под новые технологии и продолжить улучшать другие модули системы SEDMAX
В настоящий момент новые модули внедрены на тестовые серверы для апробации, дальнейшего развития и подготовке к отправке к заказчикам.
СПИСОК ИСПОЛЬЗОВАННЫХ ИСТОЧНИКОВ
1. Бэнкс, А. И. React и Redux: функциональная веб-разработка / А. Бэнкс, Е. Порселло. - СПб.: Питер, 2019. - 336 с.
2. СТО ВоГУ-МУ.1-2019. Выпускная квалификационная работа. Требования к структуре, содержанию и оформлению: - Введ. 19.02.2019. - Вологда: Вогу, 2019. - 67 c.
3. Дж. Резиг, Б. Бибо. Секреты JavaScript ниндзя : Пер. с англ. - М. : ООО «И.Д. Вильямс», 2013. - 416с. : ил. - Парал. тит. англ.
ПРИЛОЖЕНИЕ
Запросы к Application Program Interface для модуля «Виджеты»
export function* requestCreateWidget(action) {
const { params } = action;
try {
const response = yield call(createWidget, params);
const { data } = response;
yield put(createWidgetResponse(fromJS(data)));
yield* requestWidgetsList();
} catch (error) {
const statusCode = error.response.status;
errorsHandling(statusCode, 'action');
yield put(createWidgetFailed(error));
}
}
export function* requestWidget(action) {
const { id } = action;
try {
const response = yield call(getWidget, id);
const { data } = response;
let selectedOptions;
if (data.parameters !== null) {
selectedOptions = data.parameters.map(parameter =>
`${parameter.object_id}_${parameter.device_id}_${parameter.ti_id}`
);
} else {
selectedOptions = new Set();
}
const dataModified = {
...data,
selectedOptions: new Set(selectedOptions),
selectedNodes: []
};
yield put(widgetResponse(fromJS(dataModified)));
}
catch (error) {
const statusCode = error.response.status;
errorsHandling(statusCode);
yield put(widgetFailed(error));
}
}
export function* requestUpdateWidget(action) {
const { id, params } = action;
try {
const response = yield call(updateWidget, id, params);
const { data } = response;
yield put(updateWidgetResponse(fromJS(data)));
yield* requestWidgetsList();
} catch (error) {
const statusCode = error.response.status;
errorsHandling(statusCode, 'action');
yield put(updateWidgetFailed(error));
}
}
export function* requestDeleteWidget(action) {
const { id } = action;
try {
const response = yield call(deleteWidget, id);
const { data } = response;