0Pricing
R Academy · บทเรียน

การทดสอบหน่วยด้วย testthat

เขียนบล็อก test_that() ใช้ข้อคาดหมาย และเรียกใช้ tests ด้วย devtools::test()

การทดสอบหน่วยด้วย testthat เป็นบทเรียน R Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน R Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส R Academy มีบทเรียนทั้งหมด 4 บทเรียน

เหตุใดจึงต้องทดสอบหน่วย

การทดสอบหน่วยจะตรวจสอบโดยอัตโนมัติว่าฟังก์ชันแต่ละรายการทำงานได้ถูกต้องหรือไม่ การทดสอบช่วยตรวจจับการถดถอยเมื่อคุณเปลี่ยนโค้ด ทำหน้าที่เป็นเอกสารประกอบที่เรียกใช้ได้ และช่วยให้คุณปรับโครงสร้างโค้ดใหม่ได้อย่างมั่นใจและปลอดภัย แพ็กเกจ testthat เป็นกรอบงานมาตรฐานสำหรับการทดสอบแพ็กเกจ R

การตั้งค่า testthat

usethis::use_testthat() จะเพิ่ม testthat ลงใน Suggests ใน DESCRIPTION สร้าง tests/testthat/ และสร้างสคริปต์ตัวเรียกใช้ tests/testthat.R ให้เรียกใช้คำสั่งนี้หนึ่งครั้งเมื่อเริ่มต้นแพ็กเกจใหม่

# usethis::use_testthat()
#
# Creates:
# tests/
#   testthat.R                  <- runner (do not edit)
#   testthat/
#     (empty — write test files here)
#
# Updates DESCRIPTION:
# Suggests: testthat (>= 3.0.0)
# Config/testthat/edition: 3

การสร้างไฟล์การทดสอบ

usethis::use_test('add') จะสร้าง tests/testthat/test-add.R ตามธรรมเนียม ไฟล์การทดสอบจะตั้งชื่อเป็น test-{function_name}.R แต่ละไฟล์จะรวมการทดสอบสำหรับฟังก์ชันหรือความสามารถหนึ่งรายการ

# usethis::use_test('add')  # creates tests/testthat/test-add.R
#
# Content of test-add.R:
# test_that('add() returns correct sum', {
#   expect_equal(add(1, 2), 3)
#   expect_equal(add(-1, 1), 0)
#   expect_equal(add(0.1, 0.2), 0.3, tolerance = 1e-7)
# })

โครงสร้าง test_that()

test_that('description', { ... }) ใช้จัดกลุ่มสิ่งที่คาดหวังที่เกี่ยวข้องกัน สตริงคำอธิบายควรเติมประโยค 'test that ...' ให้สมบูรณ์ และต้องเฉพาะเจาะจงมากพอที่จะเป็นประโยชน์ในข้อความแจ้งเมื่อการทดสอบล้มเหลว

# Good test_that descriptions:
# test_that('add() handles negative numbers', { ... })
# test_that('add() recycles length-1 vectors', { ... })
# test_that('add() returns NA when input contains NA', { ... })
#
# Bad (too vague):
# test_that('it works', { ... })
# test_that('test1', { ... })

expect_equal() และ expect_identical()

expect_equal(actual, expected) ทดสอบโดยยอมให้มีค่าคลาดเคลื่อนทางตัวเลขสำหรับเลขทศนิยม expect_identical(actual, expected) ต้องการความเท่ากันทุกประการ รวมถึงชนิดข้อมูลด้วย ในกรณีส่วนใหญ่ ควรใช้ expect_equal() มากกว่า

# test_that('add() adds correctly', {
#   expect_equal(add(1, 2), 3)            # numeric equality
#   expect_equal(add(0.1, 0.2), 0.3)     # tolerance handles floating point
#   expect_identical(add(1L, 2L), 3L)    # exact type match: integer
#   expect_identical(add(1.0, 2.0), 3.0) # exact type match: double
# })

expect_error() และ expect_warning()

ทดสอบว่าฟังก์ชันสร้างข้อผิดพลาดและคำเตือนที่ถูกต้องหรือไม่ ส่งรูปแบบ regex เพื่อจับคู่กับข้อความข้อผิดพลาด — วิธีนี้ช่วยยืนยันว่าเป็นข้อผิดพลาดที่ถูกต้อง ไม่ใช่ข้อผิดพลาดใด ๆ ก็ได้

# test_that('add() validates input types', {
#   expect_error(
#     add('a', 2),
#     regexp = 'numeric'   # message must contain 'numeric'
#   )
#   expect_error(
#     add(NULL, 1),
#     regexp = 'numeric'
#   )
# })
#
# test_that('sqrt() warns on negative input', {
#   expect_warning(sqrt(-1))
# })

expect_true() และ expect_false()

expect_true(expr) และ expect_false(expr) ใช้ทดสอบเงื่อนไขตรรกะ ใช้ฟังก์ชันเหล่านี้เมื่อทดสอบเพรดิเคตหรือเงื่อนไขที่ส่งกลับค่าตรรกะเดียว

# test_that('is_positive() returns correct logical', {
#   expect_true(is_positive(5))
#   expect_true(is_positive(0.001))
#   expect_false(is_positive(0))
#   expect_false(is_positive(-3))
# })
#
# # Also useful for vector tests:
# test_that('add() result has correct length', {
#   result <- add(c(1,2,3), c(4,5,6))
#   expect_true(length(result) == 3)
# })

ฟังก์ชันตรวจสอบสิ่งที่คาดหวังเพิ่มเติม

testthat มีฟังก์ชันตรวจสอบสิ่งที่คาดหวังมากมายสำหรับสถานการณ์ต่าง ๆ:

  • expect_length(x, n) — ตรวจสอบความยาวเวกเตอร์
  • expect_type(x, 'double') — ตรวจสอบชนิดพื้นฐาน
  • expect_s3_class(x, 'data.frame') — ตรวจสอบคลาส S3
  • expect_null(x) — ตรวจสอบว่าเป็น NULL
  • expect_match(string, regexp) — ตรวจสอบรูปแบบสตริง
# test_that('add() output has correct type and length', {
#   result <- add(c(1.0, 2.0), c(3.0, 4.0))
#   expect_type(result, 'double')
#   expect_length(result, 2)
# })
#
# test_that('summary_stats() returns a data frame', {
#   result <- summary_stats(rnorm(100))
#   expect_s3_class(result, 'data.frame')
# })

การเรียกใช้การทดสอบด้วย devtools::test()

devtools::test() (Ctrl+Shift+T) เรียกใช้ไฟล์การทดสอบทั้งหมดและแสดงสรุปการทดสอบที่ผ่าน ล้มเหลว และคำเตือน การทดสอบแต่ละรายการที่ล้มเหลวจะแสดงสิ่งที่คาดหวังที่ไม่ผ่าน รวมถึงค่าจริงเทียบกับค่าที่คาดหวัง

# devtools::test()
#
# Example output:
# == Testing mypackage ====================================
# v | OK F W S | Context
# v |  3       | add [0.1s]
# v |  4       | subtract [0.1s]
# x |  2 1     | multiply [0.2s]
# -- Failure (test-multiply.R:5): multiply() handles zero
# multiply(5, 0) not equal to 0.
# Actual:   5
# Expected: 0
# ==========================================================
# [ FAIL 1 | WARN 0 | SKIP 0 | PASS 9 ]

ความครอบคลุมการทดสอบด้วย covr

covr::package_coverage() วัดเปอร์เซ็นต์ของบรรทัดในแพ็กเกจที่การทดสอบเรียกใช้ covr::report() จะเปิดรายงาน HTML ที่แสดงบรรทัดที่ครอบคลุม (สีเขียว) และไม่ครอบคลุม (สีแดง) ควรตั้งเป้าให้มีความครอบคลุมอย่างน้อย 80%

# library(covr)
# cov <- package_coverage()
# print(cov)
#
# Example output:
# mypackage Coverage: 87.50%
# R/add.R:      100.00%
# R/subtract.R: 100.00%
# R/utils.R:     62.50%  <- needs more tests!
#
# covr::report()  # interactive HTML report
# covr::zero_coverage(cov)  # list uncovered lines

การทดสอบกรณีขอบเขต

การทดสอบที่ดีไม่ควรครอบคลุมเฉพาะเส้นทางปกติที่ทุกอย่างเป็นไปด้วยดี แต่ควรครอบคลุมกรณีขอบเขตด้วย:

  • อินพุตว่าง: numeric(0), character(0)
  • อินพุต NA: ฟังก์ชันส่งต่อหรือจัดการ NA อย่างไร
  • อินพุตที่มีความยาว 1 เทียบกับความยาว n
  • ค่าขอบเขต: 0 จำนวนติดลบ ค่าที่มีขนาดใหญ่มาก
  • ชนิดข้อมูลไม่ถูกต้อง: จะเกิดอะไรขึ้นเมื่อผู้ใช้ส่งสตริงให้ฟังก์ชันที่รับค่าตัวเลข
# test_that('add() handles edge cases', {
#   expect_equal(add(numeric(0), numeric(0)), numeric(0))  # empty
#   expect_true(is.na(add(NA, 1)))                        # NA propagation
#   expect_equal(add(1, c(1,2,3)), c(2,3,4))              # recycling
#   expect_equal(add(.Machine$integer.max, 0L),           # boundary
#               .Machine$integer.max)
# })

ตรวจสอบอย่างรวดเร็ว: expect_error()

คุณเรียกใช้ expect_error(my_fn('bad'), regexp = 'invalid input') การทดสอบนี้ตรวจสอบอะไร

ทบทวนการทดสอบหน่วย

การทดสอบแพ็กเกจ R ด้วย testthat:

  • usethis::use_testthat() — ตั้งค่าโครงสร้างพื้นฐานสำหรับการทดสอบเพียงครั้งเดียว
  • usethis::use_test('fn') — สร้าง tests/testthat/test-fn.R
  • test_that('description', {...}) — จัดกลุ่มข้อคาดหมายที่เกี่ยวข้องกัน
  • expect_equal(), expect_error(), expect_warning(), expect_true(), expect_false() — ฟังก์ชันข้อคาดหมายหลัก
  • devtools::test() — เรียกใช้การทดสอบทั้งหมด (Ctrl+Shift+T)
  • covr::package_coverage() — วัดความครอบคลุมของการทดสอบ

คำถามที่พบบ่อย

บทเรียน “การทดสอบหน่วยด้วย testthat” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การทดสอบหน่วยด้วย testthat” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส R Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส R Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การทดสอบหน่วยด้วย testthat”

เขียนบล็อก test_that() ใช้ข้อคาดหมาย และเรียกใช้ tests ด้วย devtools::test() คุณปฏิบัติ R Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน R Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน R Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน

บทเรียน “การทดสอบหน่วยด้วย testthat” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน R Academy นี้ได้ไหม

ได้ บทเรียน R Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. โครงสร้างแพ็กเกจด้วย usethis และ devtools
  2. การจัดทำเอกสารฟังก์ชันด้วย roxygen2
  3. การทดสอบหน่วยด้วย testthat
  4. การส่งแพ็กเกจไปยัง CRAN และการบำรุงรักษา
← กลับไปที่ R Academy