问题描述
已经有一些关于 pImpl 习语及其用法对应用可测试性的意义的阅读资料(例如,请参阅:The pImpl idiom and Testability)。虽然最常见的“官方”答案总是类似于:“隐藏在 pImpl 构造后面的所有内容都不是为了让您测试。假设代码的一部分是合理的,然后对可用部分进行黑盒测试代码”,当隐藏在不透明指针后面的是 GUI(或其他有价值的对象)时,我无法找到一种方法(或常见做法)让单元测试与不透明指针共存。稍后与代码的“可用”部分(即调用方方法)进行交互的用户类型的交互。
特别是,我正在考虑 Qt 隐藏使用 Qt Creator 设计的小部件/对话框的实现的不透明指针。假设我有一个带有文本显示和“新建”按钮的主窗口。如果我按下按钮,则会出现一个带有 lineEdit 和 buttonBox(确定/取消)的新对话框。如果我在 lineEdit 中写入一些文本并按“确定”,则新对话框将关闭,文本将显示在主窗口的文本显示中。如果我在新对话框中按“取消”(不管 lineEdit 中的文本如何),对话框将关闭,没有进一步的影响。
上述简单程序的设计如下:
//mainwindow.h
#pragma once
#include <QMainWindow>
...
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
newDialog* newdialog;
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_buttonNew_clicked();
private:
Ui::MainWindow *ui;
};
ui
对象(命名空间 MainWindow
中名为 Ui
的类)的实际实现可以在头文件 ui_mainwindow.h
中找到,Qt 会根据该头文件自动生成XML 文件,但这对当前问题并不重要。
MainWindow
源文件提供了一个专用槽,用于调用新的对话框类并收集用户输入的文本,以防用户单击“确定”:
//mainwindow.cpp
...
void MainWindow::on_buttonNew_clicked()
{
int res;
this->newdialog = new newDialog(this);
res = newdialog->exec();
if (res == QDialog::Rejected)
{
// do nothing
return;
}
QString newDialogText = newdialog->get_text();
// set newDialog text in mainwindow text display
}
//newdialog.cpp
#include "newdialog.h"
#include "ui_newdialog.h"
newDialog::newDialog(QWidget *parent) : QDialog(parent),ui(new Ui::newDialog)
{
ui->setupUi(this);
}
newDialog::~newDialog()
{
delete ui;
}
void newDialog::on_buttonBox_rejected()
{
reject();
}
void newDialog::on_buttonBox_accepted()
{
accept();
}
QString newDialog::get_text()
{
QString text = ui->lineEdit->text();
return text;
}
//newdialog.h
#pragma once
#include <QDialog>
namespace Ui {
class newDialog;
}
class newDialog : public QDialog
{
Q_OBJECT
public:
explicit newDialog(QWidget *parent = nullptr);
~newDialog();
QString get_text();
private slots:
void on_buttonBox_rejected();
void on_buttonBox_accepted();
private:
Ui::newIssue *ui;
};
最后,newDialog
类的(隐藏)实现,在头文件 ui_newdialog.h
中:
//ui_newdialog.h
#ifndef UI_NEWDIALOG_H
#define UI_NEWDIALOG_H
#include <QtCore/QVariant>
...
QT_BEGIN_NAMESPACE
class Ui_newDialog
{
public:
QLineEdit *lineedit;
QDialogButtonBox *buttonBox;
void setupUi(QDialog *newDialog)
{
...
}
void retranslateUi(QDialog *newDialog)
{
...
}
};
namespace Ui {
class newDialog: public Ui_newDialog {};
}
QT_END_NAMESPACE
#endif
现在,我似乎无法理解以下内容。我想测试 MainWindow::on_buttonNew_clicked()
方法。在我的测试类的头文件中,我声明了一个 MainWindow*
实例,并且由于 MainWindow
类将 newDialog* newdialog;
声明为公共成员,我可以从我的测试中访问新的对话框公共方法类(即只有 newDialog::get_text()
)。
尽管如此,在测试期间,我想自动向新对话框提供一些虚拟文本,以查看是否例如它被正确解析到主窗口 newDialogText
变量中。为此,QTest
提供了一些功能,例如QTest::mouseClick(...,Qt::LeftButton)
,但是:
- 如果对
lineedit
或buttonBox
的实际访问受 pImpl 保护,我应该如何使用它? - 有没有什么方法可以在不撤消 pImpl 的情况下执行此测试?
- “你不应该测试这个”是否仍然适用于这个案例?
- 我的软件设计是否从根本上是错误的,这是因为我遇到了这种情况?
任何帮助将不胜感激。提前致谢。
编辑 1:
将 friend
声明添加到 newDialog
类没有帮助。这是:
//ui_newdialog.h
...
namespace Ui {
class newDialog: public Ui_newDialog
{
friend class TestMainWindow;
};
}
代替:
//ui_newdialog.h
...
namespace Ui {
class newDialog: public Ui_newDialog {};
}
其中 TestMainWindow
显然是将运行测试的类。
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)