Цель тестирования: Подтвердить, что система реализована в соответствии с предъявленными к ней функциональными требованиями и полностью готова к работе, при этом система воспринимается как единый «чёрный ящик».
Главное преимущества такого тестирования - это имитация фактического использования системы, однако есть и недостатки, такие как возможность упущения логических ошибок в программном обеспечении и вероятность избыточного тестирования.
Исходные данные и результаты тестирования приведены в Таблице 4.1. Графа
оценка определяет соответствие результатов ожидаемым («+» - соответствуют, «-»
- нет).
Таблица 4.1 - Исходные данные и результаты тестирования программной системы
|
Исходные данные |
Результат |
Оценка |
|
Запуск инсталлятора |
Запускается установка клиента,по результатам ее выполнения пользователю предлагается ознакомится с основными ее результатами |
+ |
|
Запук исполняемого файла клиента |
Открывается приложения и начинается проверка обновлений, по ее завершению запускается главное окно |
+ |
|
Нажатие на пунк меню |
Открывается выбранное подменю |
+ |
|
Изменение параметро системы |
После сохранения именений результат успешно применяется |
+ |
|
Запуск обновления |
Запускается подсистема обновлений |
+ |
|
Измнение размеров окна программы |
Изменения применяются, пропорции отображаемого материала сохраняются |
+ |
|
Нажатие на попункт меню "Печать в PDF" |
Открывается диалоговое окно печати с возможностью выбора параметров |
+ |
|
Нажатие на понкт меню "Помощ" |
Открывается информационное окно "О программе" |
+ |
|
Изменение адреса получения обновлений на локальный |
Программа меняет протокол обмена данными и получает обновления из локальной папки |
+ |
|
Переход по ссылке в МИС на открытие тектового файла |
Идет загрузка фала, затем его открытие в выбранном тектовом редакторе. |
+ |
|
Переход по ссылке в МИС на прямую печать тектового файла |
Идет загрузка фала, затем его преобразование в pdf формат и отправка на принтер. От пользователя скрыт весь процесс. |
|
|
Нажание на подпунк меню "Выход" |
Программа закрывается |
+ |
4.3 Тестирование модульной расширяемости
Для изменения логики работы всей системы достаточно в ее параметрах
указать название другого модуля главного окна. На рисунке 4.2 представлен
пример работы главного модуля, которы имеет название
"InterinClntMainWnd_2.0.10.dll ".
Рисунок 4.2 - Пример работы модуля
"InterinClntMainWnd_2.0.10.dll"
На рисунке 4.3 представлен процесс изменения главного исполнемого модуля
на "InterinClntMainWnd_2.0.4.dll".
Рисунок 4.3 - Пример изменения главного исполняемого модуля
После применения измений и перезапуска программы можно увидеть, что система успешно запустилась, однако функционал сущеественно ограничен, поскольку был подключен устаревший модуль.
На рисунке 4.4 представлен пример работы главного модуля, которы имеет
название "InterinClntMainWnd_2.0.4.dll ".
Рисунок 4.4 - Пример работы модуля
"InterinClntMainWnd_2.0.4.dll"
Для расширения функиционала системы путем добавления бибилотек, а не их изменения потребуется в реестре операционной системы, в ветви "ModulesManeger" создать раздел. В нем разделе необхоимо создать такие параметры как module_path,module_name и version. В module_path необходимо указать полный путь до ибилотеки, а в module_name её полное наименование. После перезапуска программы, функционал реалиованный в данной бибилотеке будет доступен.
Для внедрения клиента корпоративной информационной системы необходимо
происталлировать програмный продукт на все необходимые рабочие места и насроить
адрес домашней страницы. Далее, при необходимости, нужно установить программы
для работы с тектовыми документами, а так же выбрать нужную в настройках. Для
этого в настройках системы, в пункте "Редактор выходных форм"
необходимо выбрать исполняемый файл тектового редактора. Данный процесс
представлен на рисунке 5.1.
Рисунок 5.1 - Пример выбора редактора выходны фаорм
Вторым этапом внедрения является создание общего ресурса, на котором будет рассположены файлы обновления с их описанием. Разработанная подсистема обновлений позволяет без изменений использовать раличные протоколы обмена данными, такие как ftp,smb,file. Таким образом, необходимо только указать в настройках путь до папки с обновлениями.
На рисунке 5.2 представлен пример отображения медицинской информационной
системы Interin PROMIS ALPHA на реализованном в данной работе клиенском
приложениии.

Рисунок 5.2 - Вид типовой МИС
В данной магистерской диссертации была проведена работа по анализу методов реализации клиента информационной веб-системы, а так же выбран оптимальный способ его реализации. Была представлена и реализована идея интеграции информационных решений, для получения многофункционального, конкурентноспособного программного продукта. Разработана модульная структура, которая отражена на функциональной и структурной схемах. Она позволяет обеспечить легкое обновление, тиражируемость и масштабируемость всей системы без изменения основных компонент.
Реализованы основные модули системы, такие как ее ядро и главное окно. Реализованный метод интеграции предполагает обязательное наличие в системе только этих двух компонент, а остальные исключительно для наращивания функционала. Для расширения возможностей был разработан модуль печати, который основан на сторонней библиотеке, что показывает интеграционные способности всей системы, а подсистема обновлений предоставляет широкий выбор настроек для поддержания всех модулей в актуальном состоянии. Так же продемонстрирована стабильная работоспособность всей системы и возможность изменения ее функционирования путем подключения или отключения бибилотек.
Полученный программный продукт полностью удовлетворяет всем исходным требования и используется в качестве клиента медицинской информационной системы «Interin PROMIS ALPHA» в двух медицинских организацияхж
Результаты работы представляют высокую практическую значимость, поскольку разработанный клиент предоставляет возможность быстрой адаптации к различным информационным системам, путем изменения отдельных библиотек, что позволяет не просто расширять его функционал, а полностью изменять логику работы системы.
(Обязательное)
Исходный код функции main ядра системы
#include "../src/InterinClntApp/interinclntapp.h"main(int argc, char **argv)
{InterinClntApp *app=Q_NULLPTR;
QString execAfterExit="";
char initRez;
bool done=false;
app=new InterinClntApp(argc, argv);
while(!done){
initRez=app->init();
if(!initRez){
execAfterExit=" Не удалось выполнить инициализацию параметров приложения.\n"
" Работа будет завершена. Обратитесь в техподдержку!";
if(app->getAppLog())
app->getAppLog()->toLog(0)<<execAfterExit<<endl;
QMessageBox::critical(0, QString(" Клиент МИС \"Интерин\" версия ")+
app->applicationVersion(), execAfterExit,
QMessageBox::Ok);
delete app;
return 1;
}
if(initRez==0x01){
if(app->loadMainModule()){
app->exec();
execAfterExit=app->getUpdateCommand();
if(!execAfterExit.isEmpty()){
app->getAppLog()->toLog(9)<<" Перезапускаемся для проверки обновлений.\n "<<execAfterExit<<endl;
initRez=0x02;
}
done=true;
}
else{
execAfterExit=" Не удалось загрузить основной модуль программы.\n"
" Нажмите Ок для загрузки основного модуля с сервера обновлений.\n"
" Нажмите Cancel для завершения работы и обратитесь в техподдержку!.";
if(app->getAppLog())
app->getAppLog()->toLog(0)<<execAfterExit<<endl;
if(QMessageBox::critical(0, QString(" Клиент МИС \"Интерин\" версия ")+
app->applicationVersion(), execAfterExit,
QMessageBox::Ok|QMessageBox::Cancel)!=QMessageBox::Ok)
done=true;
}
}
else{ execAfterExit=app->getUpdateCommand();
app->getAppLog()->toLog(9)<<" Обновились. После завершения выполняем команду\n "<<execAfterExit<<endl;
done=true;
}
}app->saveParams();
delete app;
if(!execAfterExit.isEmpty() && initRez==0x02)
QProcess(0).startDetached(execAfterExit);
return 0;
}
Исходный код менеджера модулей
#include "gsmodule.h"
GSModule::GSModule(const QString &moduleName, const QString &modulesSection,
QObject *parent):
QObject(parent)
{
setObjectName(moduleName);
m_DllInit=Q_NULLPTR;
m_DllStart=Q_NULLPTR;
m_DllStop=Q_NULLPTR;
m_DllAbout=Q_NULLPTR;
m_HandlersArray=Q_NULLPTR;
m_WidgetsArray=Q_NULLPTR;
m_Log=Q_NULLPTR;
m_ModuleParamsSection=modulesSection+"/"+objectName()+"/";
// load();
}::~GSModule()
{
unload();
m_Log=Q_NULLPTR;
}GSModule::init(void *abstractInterface)
{TGetEventsHandlers getHandlers=Q_NULLPTR;
TGetWidgetsList getWidgets=Q_NULLPTR;
QSettings objectParams;
objectParams.setValue(m_ModuleParamsSection+"version", about(ABOUT_VER));
if(!m_DllInit)
return 0x00;
if(!m_DllInit(abstractInterface, &m_ModuleParamsSection))
return 0x00;
getHandlers=(TGetEventsHandlers) m_Library.resolve("getEventsHandlers");
if(getHandlers)
m_HandlersArray=(THandlersArray *)getHandlers();
getWidgets=(TGetWidgetsList) m_Library.resolve("getWidgetsList");
if(getWidgets)
m_WidgetsArray=(TWidgetsArray *)getWidgets();
return 0x01;
}GSModule::start()
{QSettings objectParams;
if(!m_DllStart)
return 0x00;
// objectParams.setValue(m_ModuleParamsSection+"version", about(ABOUT_VER));
return m_DllStart();
}GSModule::stop()
{
m_HandlersArray=Q_NULLPTR;
m_WidgetsArray=Q_NULLPTR;
if(!m_DllStop)
return 0x00;
return m_DllStop();
}GSModule::about(char content)
{QString mess;
if(!m_DllAbout)
return "";
m_DllAbout(content, &mess);
return mess;
}GSModule::isLoaded()
{
return m_Library.isLoaded();
}GSModule::load()
{QSettings objectParams;
if(m_Library.isLoaded())
unload();_Library.setFileName(objectParams.value(m_ModuleParamsSection+"module_path","").toString()+.value(m_ModuleParamsSection+"module_file","").toString());
gsInfo(m_Log,9)<<" Загружаем файл\n "<<m_Library.fileName()<<"\n из секции\n "<<m_ModuleParamsSection<<endl;
if(!m_Library.load()){
objectParams.setValue(m_ModuleParamsSection+"version","");
return false;
}
m_DllInit= (TModuleInit) m_Library.resolve("init");
m_DllStart= (TModuleStart) m_Library.resolve("start");
m_DllStop= (TModuleStop) m_Library.resolve("stop");
m_DllAbout= (TModuleAbout) m_Library.resolve("about");
return true;
}GSModule::unload()
{
if(!m_Library.isLoaded()){
stop();
m_DllInit=Q_NULLPTR;
m_DllStart=Q_NULLPTR;
m_DllStop=Q_NULLPTR;
m_DllAbout=Q_NULLPTR;
return m_Library.unload();
}
return true;
}GSModule::onEvent(const QString &event, char param)
{TEventHandler eventHandler;
if(m_HandlersArray){
eventHandler=m_HandlersArray->value(event,Q_NULLPTR);
if(eventHandler){
eventHandler(param);
return 0x01;
}
}
return 0x00;
}*GSModule::getWidget(const QString &widgetId)
{
if(m_WidgetsArray)
return m_WidgetsArray->value(widgetId,Q_NULLPTR);
return Q_NULLPTR;
}GSModule::setLog(GSLog *log)
{
m_Log=log;
}::GSModulesManager(const QString &objectName, QObject *parent)
: QObject(parent)
{
m_ModulesSection=objectName;
setObjectName(objectName);
m_Log=Q_NULLPTR;
m_newExeName="";
m_instReceivedName="";
}::~GSModulesManager()
{
unloadAllModules();
m_Log=Q_NULLPTR;
}* GSModulesManager::loadModule(const QString &moduleName)
{GSModule* module=Q_NULLPTR;
if(moduleName.isEmpty())
return loadModule(m_MainModuleName);
gsInfo(m_Log,9)<<" Загружаем модуль "<<moduleName<<endl;
for(int i=0; i<m_lModules.size(); i++){
module=m_lModules.at(i);
if(module->objectName() == moduleName){
if(module->isLoaded())
return module;
else{
module->load();
break;
}
}
module=Q_NULLPTR;
}
if(!module){
module=new GSModule(moduleName, m_ModulesSection, this);
module->setLog(m_Log);
module->load();
m_lModules.append(module);
}
return module;
}GSModulesManager::loadAllModules(void *abstractInterface, bool doInit)
{QSettings params;
GSModule* module=Q_NULLPTR;
QStringList modules;
params.beginGroup(m_ModulesSection);
modules=params.childGroups();
int index=modules.indexOf(m_MainModuleName);
if(index>0){
modules[index]=modules[0];
modules[0]=m_MainModuleName;
}
gsInfo(m_Log, 9)<<" Загружаем все модули."<<endl;
for(int i=0; i<modules.size(); ++i){
module=loadModule(modules.at(i));
if(!module->isLoaded()){
gsInfo(m_Log, 9)<<" Модуль "<<modules.at(i)<<" не загружен. Необходимо получить обновление."<<endl;
continue;
}
if(doInit)
if(!module->init((void *)this))
gsInfo(m_Log,0)<<" Не удалось проинициализировать модуль: "<<module->objectName()<<endl;
}
}GSModulesManager::unloadModule(GSModule *module)
{
for(int i = 0; i<m_lModules.size(); ++i){
if(module == m_lModules.at(i)){
module=m_lModules.takeAt(i);
delete module;
return;
}
}
}GSModulesManager::unloadAllModules()
{GSModule *module;
bool ok=false;
gsInfo(m_Log, 9)<<" Выгружаем все модули. Общее число загруженных модулей "<<m_lModules.size()<<"."<<endl;
while(!m_lModules.isEmpty())
delete m_lModules.takeFirst();
}GSModulesManager::setLog(GSLog *log)