בדיקות

From GnuCash
Jump to: navigation, search
שפות אנגלית גרמנית ספרדית עִברִית פורטוגזית צרפתית

כללי

מערכת בדיקות טובה היא דרישה קריטית לפיתוח תוכנה מודרני, הן כדי להבטיח את איכות המוצר והן כדי לעזור למפתחים לשנות קוד במהירות מבלי להכניס תקלים או לגרום לנסיגה בקוד. הספרות על בדיקות תוכנה היא עצומה; מדריכים והפניות מצוינים זמינים הן במרשתת והן בדפוס, ראו סקירת ספרות.

כל המפתחים מוזמנים לבצע בדיקות ולוודא שכל תוכנית מכוסה הן על ידי בדיקות קבלה ובדיקות יחידה.

ארכיטקטורת בדיקות נוכחית

בדיקות קבלה

בדיקות הקבלה בגנוקאש מבוססים על קבוצת קובצי מקרו ופונקציות תוצרת בית (או מקור אנונימיים) אותם ניתן למצוא בתקיות src/test-core ו- src/engine/test-core. האיכות, ההיקף והכיסוי של הבדיקות משתנה מאוד; חלקים מסוימים של גנוקאש נבדקים בשטחיות או בכלל לא בעוד שחלקים אחרים נבדקים בהרחבה ובאופן מעמיק למדי. למרות שהן מתוייגות כ"מבחני קבלה", במקרים רבים הם נכתבים יותר כבדיקות יחידה המקיפים פונקציה אחת ולא פירקן שלם.

בדיקות יחידה

מבחינה רעיונית בדיקות יחידה שוברות תוכנית לחתיכות בדידות ובודקות כל חלק בנפרד, בדיקות היחידה הם בדרך כלל קטנים ולא נדרש זמן רב לכתיבן מכיוון שהם בודקים רק קטע קטן של קוד המקור. קנט בק[1], אחד מחותמי המניפסט האג'אלי [2] בראשית שנות התשעים של המאה הקודמת, אפילו הקצין את הפילוסופיה של פיתוח תוכנה, לכתיבת בדיקות יחידה לפני כתיבת הקוד עצמו - המכונה פיתוח מונחה-בדיקות [3] - שעדיין נמצאה בשימוש כיום.

יש לבדוק את כל הפונקציות המשתתפות בקוד, תוך שונות פרמטרים רבה ככל האפשר, עם דגש על מקרי קיצון. בדיקות לא צריכות להיות תלויות ביישום עצמו וזאת כדי למנוע פריכות הבדיקה.

גנוקאש אמצה את GLib testing framework לביצוע בדיקות יחידה של GObject-based classes ו- GLib-dependent קוד. מוסלים צ'וקולוב כתב בדיקות יחידה עבור הפירקנים החשובים ביותר ב LibQOF כ- פרויקט GSoC2011. העבודה ממשיכה לקבל את כל LibQOF והמנוע נבדק במלואו כדי להקל על שינויי ארכיטקטורה גדולים הנחוצים כדי להפוך את גנוקאש ליישום מסד נתונים ראוי.

לפתוח בקוד C++ גנוקאש אמצא את מסגרת הבדיקות של גוגל.

ראו גם https://developer.gnome.org/glib/stable/gtester.html לכלי פקודת השורה להרצת בדיקות בפועל.

הרצת בדיקות

 make check

או

 ninja check

בונה ומריצה את ערכת הבדיקה המלאה.

נ.ב. בדיקות מסוימות תלויות בספריות נוספות והמטרה המובנית של cmake לא בונה אותם. לאחר שהיעד check נבנה, check ו- test הם מילים נרדפות.

יעדים אלה מריצים את הבדיקות באמצעות הפקודה ctest. ברירת המחדל שלה היא להריץ את כל הבדיקות ולכתוב את הפלט אל CMAKE_BUILD_DIRECTORY/Testing/Temporary/LastTest.log. ניתן לבטל את שניהם באמצעות אפשרויות שורת פקודה, כגון.

 ctest -V -R test-engine

יריץ את כל הבדיקות ששמות היעד שלהן מתחילים ב- test-engine ויפיק את התוצאות ל- stderr. ניתן לבנות בדיקות בודדות על ידי ציון מטרותיהם, למשל.

 ninja test-gnc-timezone

ולאלו שכתובים ב- C ומייצרים קובץ הפעלה ניתנים להפעלה ישירות:

 bin/test-gnc-timezone

בעוד לאלו שלא, ניתנים להפעלה באמצעות הפקודה:

 ctest -R

Travis CI

We have set up an automatic build and test bot on Travis CI to run the full test suite after every commit and for every Github pull request. The Travis build and test environment is configured through the .travis.yml file in the GnuCash root directory. Individuals with Github forks can easily arrange to run Travis on commits to their repositories as well from the Github repository's Settings Tab: Select Integrations & Services then select Travis CI from the drop down list, enter your password, and fill out the form.

Travis keeps track of the status of each branch's last test and will email the pusher if a push fails to build or test or if the previous push failed and the latest one didn't. Obviously if Travis reports that the branch is fixed no action is required. If Travis reports a failure, follow the link in the email and examine the output. If it indicates a problem with the commit then you should push a fix, but sometimes it will indicate an unrelated error. There are some tests that fail at random; you can look at the build history tab on the Travis page to see old failures and to compare the failing tests to see which tests they are. In those cases rerunning the build on Travis (the button is at the top left of the build page) will usually produce a passing test and a happy Travis.

For tests that fail on Travis but not on your local development system it can be helpful to keep a VM around that duplicates the Travis build environment, which you can determine by examining .travis.yml. Note that the default Travis environment is Ubuntu Precise (12.04), which maint uses; master changes that to Ubuntu Trusty (14.04) via the .travis.yml

 dist: trusty

מדיניות

  • כל הקוד החדש שאינו מנשק-משתמש חייב לכלול בדיקות יחידה יסודיות. בדיקות אוטומטיות של מנשק-המשתמש נוטות להיות 'פריכות', לכן יש לבדוק את שינויי מנשק-משתמש באופן ידני בכמה שיותר סביבות מערכות הפעלה לפני שהם מהודרים.
  • הפעלת make check מתקיית הבנייה העליונה צריכה לעבור (הצלחה) לפני שהידורים נדחפים לענף.

מדיניות בדיקות יחידה

  • אין צורך לבדוק פונקציות Getter/Setter המגדירות או מאחזרות רק משתנה מופע.
  • פונקציות נוחות ש רק עוטפות פונקציה אחרת כדי לשנות את שם הפונקציה או לספק משתנה ברירת מחדל אינן דורשות בדיקה.
  • אין צורך לבדוק פונקציות מורכבות, או פונקציות שרק משרשרות סדרת קריאה לפונקציות אחרות אם הפונקציות הנקראות נבדקות, ואין להן כל תופעות לוואי, וכאשר לפונקציה המורכבת יש רק תזרים סקרה אחד.
  • קיימת מחלוקת מסוימת בקרב גורואי הבדיקות לגבי השאלה, האם יש לממש את שונות משתני פונקציה בפונקציית בדיקה אחת, או בפונקציית בדיקה נפרדת לכל קריאה לפונקציה. נא להשתמש בשיקול הדעת במקרה זה. נא לזכור כי ההנחיה של פיתוח זריז היא לכתוב קצת בכל פעם ולשנות מחדש כמה פעמים שצריך. הכלל הזה חל במידה שווה על קוד הבדיקה כמו על קוד הייצור. זה בסדר לשנות את דעתכם!
  • באופן דומה יש מתח בקרב הגורואים בסוגיה עד כמה תכנית בדיקה צריכה להיות תלויה בקוד אמיתי וכמה להשתמש באובייקטים מדומים להחלפת קוד כזה. בהתחשב במטרת מחזור קצר של הידור קוד, השתמשו בשיקול הדעכם. עם זאת, נכון לעכשיו חלקים גדולים מגנוקאש תלויים זה בזה ואינם ניתנים להדמית פונקציות - דרישה ליישום מדמים. אם אתם כותבים פורקנים חדשים, השתמשו בטכניקות OO מודרניות כדי למזער תלות הדדית, ובמקרה הצורך נא להקפד להשתמש בפונקציות מדומות כך שלא יהיה צורך לקשר בין שאר גנוקאש כדי לבדוק את הקוד שכתבתם.

כתיבת בדיקות

בדיקות המבוססות על בדיקות גוגל

בדיקות לקוד שנכתב ב- ++C צריכות להכתב תוך שימוש ב- GoogleTest ו- GoogleMock.

There are plenty of websites devoted to writing unit tests. There are also a couple of encyclopedic books on the topic, XUnit Test Patterns by George Mezaros and Working Effectively With Legacy Code by Michael Feathers.

Tests should be written in a test subdirectory of the directory containing the implementation file that you're testing. Create one if it doesn't already exist.

Once you've written your test you need to arrange for it to be compiled and run by the build system. The test directory needs a CMakeLists.txt if it doesn't already have one.

There's a handy function, gnc_add_test() that takes care of most of the boilerplate of adding a test to the build system. It takes four arguments: The test name, which must be unique in the whole build system and should be test-file-name where "file-name" is the file containing the functions you're testing; the source files for the test; a variable containing the include paths; and a variable containing the library flags and other cmake targets that the test depends upon. For example, suppose that we want to test foodir/foo.c. This file calls functions in libgncmod-engine and needs to include files from the libgnucash/engine directory. We'd use the following setup in CMakeLists.txt:

 set(test_foo_SOURCES ../foo.c test-foo.c)
 set(test_foo_INCLUDES ${CMAKE_SOURCE_DIR}/libgnucash/engine)
 set(test_foo_LIBS gncmod-engine)
 gnc_add_test(test-foo "${test_foo_SOURCES}" test_foo_INCLUDES test_foo_LIBS)

That gets the test built and run. We also need to make sure that the source files are included in the distribution tarball, so at the bottom of CMakeLists.txt we need:

 set(test_foodir_sources_DIST "${test_foo_SOURCES}")
 set(test_foodir_DIST CMakeLists.txt "${test_foodir_sources_DIST})

And in foodir/CMakeLists.txt:

  set(foodir_DIST "${foodir_local_DIST}" "${test_foodir_DIST}" PARENT_SCOPE)

Finally, don't forget to add all of your new files to git when you commit your test!

בדיקות מבוססות glib-test

Several of our C libraries have unit tests written using the GLib test framework. While GoogleTest is preferred for writing new tests for C++ code it may be useful to write tests using this framework for C code before converting it to C++ to help prevent breaking something. This is still unit testing so the general references above still apply.

להגדרת בדיקות יחידה בתקיה:

  • יצירת תקיית "בדיקה" במידה ואחת כזאת טרם קיימת
  • יצירת רשימת CMakeLists.txt בתיקיית הבדיקה, שוב, רק במקרה ועדין לא קיימת.
  • הגדרת תכנית בדיקה GLib ב- CMakeLists.txt זהה לזאת של בדיקות GoogleTest, ראו מעלה.
  • העתקת test-templates/test-module.c לתקיית הבדיקה שייצרתם, שנו את שמה, וצרו עבורה יעד ב- CMakeLists.txt
  • הרצה
 test-templates/make-testfile "שמכם <כתובת@yדואל.email.address>" נתיב/אל/המקור

העברת הנתיב לקובץ המקור עבורו אתם רוצים להכין בדיקה. This will create a template test file for you with all of the necessary functions prototyped and commented out and a populated test suite function with the individual tests commented out.

  • Uncomment the definition for a function that you want to test and write your test function. Write Setup and Teardown functions as needed. Uncomment the execution line for the test function, adjusting the setup and teardown function names as necessary, in the test suite function at the end of the file.

There is a unit test support module with some useful functions for controlling logging and signals in common/test-core. If you use it, add

 test-core

to your test program's LIBS variable or add

 ${CMAKE_SOURCE_DIR}/test-core/unittest-support.c

to the SOURCES variable; in either case add

 #include <unittest-support.h>

in your test-suite file. You have two options for the actual test programs. You can write a bunch of separate programs with a few tests each or you can group several files containing tests into a single program.

תכניות קטנות רבות

  • Make a copy of test-templates/testmain.c for each program, renaming it appriopriately, in your test directory.
  • Create fixtures and test functions and register the test functions in main(); there are comments in the file to guide you.
  • Set up a target in Makefile.am as described above for each program.

ערכות בדיקה

A test suite is a collection of test functions registered in a test-suite function; main() runs the test-suite functions. This makes it easier to group tests into separate files with a master test program file to contain main(). We'll call the master test program source file the module file; it's conventionally named after the directory it's testing, e.g. test-engine.c. Normally you'll have a test-suite for each source file in the directory named utest-filename.c, e.g. utest-Split.c.

Note that as the C++ conversion progresses it may be necessary to compile some of these files as C++ in which case the extension will be .cpp instead of .c.

Legacy Tests

In addition to GoogleTest and GLib Testing based tests GnuCash has several older tests based on a private framework. Most of these are module tests rather than unit tests and most don't do a good job of localizing test failures, both of which can make debugging test failures difficult. The framework isn't well documented so if you need to get into these tests you'll need to study the source code in test-stuff.h, test-stuff.c, test-engine-stuff.h, and test-engine-stuff.cpp.

בדיקות סכימה

אנחנו מעונינים לבדוק גם סכמות. בדיקות חדשות צריכות להכתב תוך שימוש ב- SRFI-64. "Legacy" tests are just scheme forms, some are unit tests and some are larger integration tests. Until recently there was no standard style or form other than that they had to exit with 0 for success or something else for failure so that ctest can tell which pass and which fail.

Scheme tests are added to CMakeLists.txt with the command gnc_add_scheme_test; multiple tests can be added with gnc_add_scheme_tests. They don't create executables in CMAKE_BUILD_DIRECTORY/bin so to run one by itself use

 ctest -R label-regex

where label-regex is a Regular Expression not a Glob. For example

 ctest -R .*-barchart

will run all of the tests whose names end in -barchart. Adding a -V to the ctest options will send the output to stdout instead of CMAKE_BUILD_DIRECTORY/Testing/Temporary/LastTest.log

מצב כיסוי בדיקה

בדיקות יחידה

LibQOF

בוצע:

  • qofbackend
  • qofbook
  • qofinstance
  • qofobject
  • qofsession
  • gnc-date
  • kvp_frame

מנוע

בוצע:

  • חשבון
  • פיצול
  • תנועה

דרישות בדיקה ידועות

  • התקשרות חוזרת של GtkAction המאוזכרת ישירות בקבצי ממשק המשתמש של GtkBuilder זקוקה לפחות ל"בדיקת נוכחות", כך make checkתיכשל במידה והתקשורות החוזרות אינן מהודרות משום מה.

סקירת ספרות

  • Test Patterns: Refactoring Test Code The skeleton of this excellent manual for writing and improving unit tests is online; there is a pointer there for purchasing the book as well. While the book focuses on xUnit-style test frameworks (meaning jUnit and its many derivatives) most of the principles and patterns are applicable to any unit test code.

הפנייות