سؤال

بدأت في كتابة بعض الاختبارات باستخدام نظام اختبار وحدة QT.

كيف تقوم عادة بتنظيم الاختبارات؟ إنها فئة اختبار واحدة لكل فئة وحدة واحدة ، أو هل تختبر الوحدة بأكملها بفئة اختبار واحدة؟ مستندات QT تقترح اتباع الاستراتيجية السابقة.

أريد أن أكتب اختبارات لوحدة. توفر الوحدة النمطية فئة واحدة فقط سيتم استخدامها من قبل مستخدم الوحدة النمطية ، ولكن هناك الكثير من المنطق المستخلص في فئات أخرى ، والتي أود أيضًا اختبارها ، إلى جانب اختبار الفئة العامة.

المشكلة هي أن الطريقة المقترحة لـ QT لتشغيل الاختبارات المعنية QTEST_MAIN دقيق:

QTEST_MAIN(TestClass)
#include "test_class.moc"

وفي نهاية المطاف ، يكون برنامج اختبار واحد قادر على اختبار فئة اختبار واحدة فقط. ويمتص نوعًا ما لإنشاء مشاريع اختبار لكل فئة في الوحدة النمطية.

بالطبع ، يمكن للمرء إلقاء نظرة على QTEST_MAIN الماكرو ، أعد كتابته ، وتشغيل فصول اختبار أخرى. ولكن هل هناك شيء يعمل خارج الصندوق؟

حتى الآن أفعل ذلك باليد:

#include "one.h"
#include "two.h"

int main(int argc, char *argv[]) 
{ 
    QCoreApplication app(argc, argv); 
    TestOne one;
    QTest::qExec(&one, argc, argv);
    TestOne two;
    QTest::qExec(&two, argc, argv);
}
هل كانت مفيدة؟

المحلول

نعم ، يفرض QTest بنية اختبار غريبة قليلاً وهو أدنى من إطار اختبار Google/Mock. بالنسبة لمشروع واحد ، أجبر على استخدام QTest (متطلبات العميل) ، وإليك كيفية استخدامه:

  1. أقوم بتجميع كل الاختبار معًا كمشروع قالب فرعي
  2. لتسهيل إنشاء اختبارات جديدة ، أشارك الكثير من تكوين المشروع باستخدام ملف Common.PRI الذي أدرجته في كل ملف .pro
  3. إذا أمكن ، أشارك دليل ملفات الكائنات لتسريع التجميع
  4. أقوم بتشغيلهم جميعًا باستخدام برنامج نصي SD+AWK+SED.

يعد إنشاء هذه النقاط الأربع أمرًا سهلاً للغاية ويجعل استخدام QTest ممتعًا تقريبًا. هل لديك بعض المشكلات في إجراء اختبارات متعددة لا يتم حلها بواسطة التكوين الموضح أعلاه؟

PS: تشغيل الاختبارات بالطريقة التي تقوم بها ، أي استدعاء QTEST المتعددة :: QEXEC يسبب مشاكل في مفتاح سطر الأوامر -O - ستحصل فقط على نتائج للفئة الأخيرة التي تم اختبارها.

نصائح أخرى

تتعلق بالإجابة المنشورة بواسطة cjhuitt

هذا مثال يزيل الحاجة إلى استدعاء كل كائن اختبار يدويًا

أحاول تجنب أشياء مثل هذا:

MyTestClass1 t1;   t1.run();
MyTestClass2 t2;   t2.run();
//etc...

الحل الخاص بي هو السماح لكائنات الاختبار بأنها ترث من فئة أساسية تضيف نفسها إلى قائمة ثابتةثم يقوم البرنامج الرئيسي بتنفيذ جميع كائنات الاختبار في تلك القائمة. وبهذه الطريقة ، لا يلزم تغيير أي من رمز الإطار الداعم. الأشياء الوحيدة التي تغير هي فئات الاختبار نفسها.

إليكم كيف أفعل ذلك:

qtestsuite.h - فئة قاعدة لكائنات الاختبار

#ifndef QTESTSUITE_H
#define QTESTSUITE_H

#include <QObject>
#include <vector>

class QTestSuite : public QObject
{
    Q_OBJECT
public:
    static std::vector<QObject*> m_suites;

public:
    explicit QTestSuite();

};

#endif // QTESTSUITE_H

qtestsuite.cpp

#include "qtestsuite.h"
#include <iostream>

std::vector<QObject*> QTestSuite::m_suites;

QTestSuite::QTestSuite() : QObject()
{
    m_suites.push_back(this);
}

testall.cpp - يدير الاختبارات

#include "qtestsuite.h"

#include <QtTest/QtTest>
#include <iostream>

int main(int, char**)
{
    int failedSuitesCount = 0;
    std::vector<QObject*>::iterator iSuite;
    for (iSuite = QTestSuite::m_suites.begin(); iSuite != QTestSuite::m_suites.end(); iSuite++)
    {
        int result = QTest::qExec(*iSuite);
        if (result != 0)
        {
            failedSuitesCount++;
        }
    }
    return failedSuitesCount;
}

mytestsuite1.cpp - مثال على كائن اختبار ، قم بإنشاء المزيد من هذه

#include "qtestsuite.h"

#include <QtTest/QtTest>

class MyTestSuite1: public QTestSuite
{
     Q_OBJECT
private slots:
    void aTestFunction();
    void anotherTestFunction();
};

void MyTestSuite1::aTestFunction()
{
    QString str = "Hello";
    QVERIFY(str.toUpper() == "this will fail");
}

void MyTestSuite1::anotherTestFunction()
{
    QString str = "Goodbye";
    QVERIFY(str.toUpper() == "GOODBYE");
}

static MyTestSuite1 instance;  //This is where this particular test is instantiated, and thus added to the static list of test suites

#include "mytestsuite1.moc"

أيضا ، لإنشاء ملف .pro

qmake -project "CONFIG += qtestlib"

في إعدادنا مع QTest ، فعلنا بعض الأشياء لجعلها أجمل.

  • حدد فئة فرعية من QOBject التي يتم استخدامها كفئة أساسية لأي فئة جديدة للاختبار.
  • في مُنشئ تلك الفئة ، نضيف مثيل الاختبار إلى قائمة ثابتة من الاختبارات ، وفي المدمر نقوم بإزالته.
  • لدينا بعد ذلك وظيفة ثابتة تحلق من خلال الاختبارات وتشغيلها باستخدامها QTest::qExec(). (نتراكم القيم التي يتم إرجاعها في كل مرة ، وإرجاع ذلك من وظيفتنا.)
  • main() يستدعي هذه الوظيفة ، ويعيد النتيجة كنجاح/فشل.
  • أخيرًا ، في وحدة التجميع في الاختبار المحدد نفسه ، عادةً ما ندرج مثيلًا ثابتًا لتلك الفئة.

هذا الإعداد يعني أن الفصل سيتم إنشاء مثيل له من قبل main() يتم تشغيله ، لذلك سيتم إضافته إلى قائمة الفئات للاختبار عند تشغيله الرئيسي. يتطلب الإطار أن تحتاج فقط إلى ورث صفك بشكل صحيح ، وتشكيل مثيل ثابت إذا كنت تريد دائمًا تشغيله.

نقوم أيضًا بإنشاء اختبارات اختيارية أخرى أحيانًا ، تتم إضافتها بناءً على مفاتيح سطر الأوامر.

عادةً ما أقوم بتنظيم الاختبارات مع اختبار واحد قابل للتنفيذ لكل فئة قيد الاختبار.

وفي نهاية المطاف ، يكون برنامج اختبار واحد قادر على اختبار فئة اختبار واحدة فقط.

هذا أمر جيد. إنه يعزل اختباراتك عن بعضها البعض ، مما يمنع أشياء مثل التصادم في اختبار واحد من منع جميع اختباراتك الأخرى. يمكن أن يكون هذا الحادث ناتجًا عن مكون مشترك في عدة فئات قيد الاختبار. من شأن نمط الإخفاقات أن ينقلك إلى الأصل الأساسي للمشكلة. في الأساس ، لديك معلومات تشخيصية أفضل للفشل إذا كانت اختباراتك مستقلة عن بعضها البعض.

اجعل من السهل إعداد العديد من المواد التنفيذية وتشغيل كل اختبار بشكل منفصل. استخدم عداء اختبار لتفريغ جميع عمليات الاختبار.

تحديث:

لقد غيرت رأيي على هذا إلى حد ما. بمجرد حصولك على برنامج كبير مع الكثير من الاختبارات ، يصبح ربط مئات الاختبارات التنفيذية بطيئة للغاية. تفضيلي الجديد هو وضع جميع الاختبارات لمكتبة ما في عملية تنفيذ واختيار الاختبارات التي يجب استدعاؤها باستخدام وسيطات سطر الأوامر التي تم تمريرها إلى الاختبار القابل للتنفيذ.

وهذا يقلل من عدد المئات من المئات إلى العشرات ، ولكنه يحتفظ بمزايا إجراء اختبارات بشكل منفصل.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top