Neden C Kod için Birim Test Maddeleri
Birim testleri güvenilir C yazılımı oluşturmak için temel bir uygulamadır. Daha yüksek seviyeli diller aksine C, bu sorunları erken yakalar, pahalı üretim kusurları haline gelmeden önce, bir işlev tam olarak nasıl hareket etmesi gerektiği ve kodbazları tekrarlamak veya genişletmek için gereken bir uygulama sağlar.
Birçok C projesinde, özellikle gömülü sistemler, miras kodbases veya performans-kahkinci kütüphaneler, yazı testlerinin disiplini genellikle göz ardı edilir. Takımlar genellikle reklam baskı veya manuel donanım testlerine güveniyorlar.Bu onların yeri olsa da, ölçeklendirmezler ve güvenilir bir şekilde otomatikleştirilemezler.
C C C Cde Testinin Temel Prensiplerini Anlamak
İyi Bir Birim Testini Ne Yapar?
Bir birim testi, tek bir “temel” davranışı doğrulamaktadır –tip olarak bir işlev veya ilgili işlevlerin küçük bir kümesi. C, bir birim testi gerekir:
- Befram:0))[[[Dönemli)) - dosyaları veya ağ soketleri gibi diğer testlerin durumuna bağlı olmamalıdır.
- Befrade:0) ⁇ able[Dönemli[Dönemli)[Dönemli[Dönemli)[Dönemli [Dönemli))[yüz defa aynı testi çalıştırın, test edilen kodun değişmediği zaman aynı sonucu üretmelidir.
- BeFLT:0)fast[DÜT:1) – tek bir test milisaniyelerde uygulanmalıdır, böylece tam bir süit saniyede çalıştırılabilir.
- TestFLT:0) Bir şey sadece – test başarısız olursa, hangi davranışın kırıldığını hemen bilmelisiniz.
Meydanlara Tek Şey
C, yerleşik yansıma, metadata veya standart bir test kullanımı sağlamaz.Sorun bir çerçeve seçmeli, test kurulumu /teardown'da hafızayı manuel olarak yönetmelisiniz ve genellikle donanım kayıtlarını veya diğer düşük seviyeli kaynakları simüle eder. Ayrıca, C codebases sık sık sık sık sık sık sık sık sık sık sık sık sık sık sık sık sık sık sık sık sık sık sık sık sık sık sık sık sık sık sık sık sık sık sık sık sık sık sık sık sık sık sık sık sık sık sık sık sık sık sık sık sık sık sık sık sık sık sık sık sık sık test edilen modüller.
Doğru Birim Test Framework'ü seçin
C ekosistemi birkaç olgun, iyi bakımlı test çerçeveleri sunar. Seçim, projenizin kısıtlamalarına bağlıdır (embedded vs. masaüstü, takım büyüklüğü, inşa sistemi). Aşağıda en popüler seçeneklere kısa rehberlik ile bağlıdır.
| Framework | Key Strengths | Best For |
|---|---|---|
| CUnit | Minimalistic, similar to xUnit patterns, extensive assertion macros. | General‑purpose C projects, especially those that do not need mocking. |
| Unity | Extremely lightweight, single header, highly portable (works on bare metal). | Embedded systems, resource‑constrained environments. |
| CMocka | Built‑in support for mock objects and stub functions, memory leak detection. | Projects that require heavy mocking and memory safety checks. |
| Check | Clean fork‑based isolation, support for fixture setup/teardown, XML output. | Larger projects that want parallel test execution and detailed reporting. |
Çoğu yeni proje için, [[0)Üretim[Üye Olmayanlar[Üye Olmayanlar İçin Mükemmel Bir başlangıç noktasıdır.Eğer gelişmiş alay yeteneklerine ihtiyacınız varsa, CMocka (bu, Unity ile Unity ile iyi bir şekilde entegre edilir)[DÜye Olmayan API[DÜye Olmayanlar İçindekiler[DÜye Olmayanlar İçindekiler)
Temiz bir Test Ortamı
Test Dosyalar
Ortak bir kongre, kaynak ağacını birFLT altında aynaya çıkarmaktır:0) Örneğin:
src/
math.c
io.c
test/
test_math.c
test_io.c
test_all.c (optional suite runner)
Her test dosyası sadece gerekli olan en az başlık içermelidir ve DÖRT:0)never) uygulamanın (örneğin, statik fonksiyonları test etmediğiniz sürece doğrudan uygulamanız gerekir (birFLT:3 başlığıyla bunları açığa çıkararak en iyi şekilde kaçınılmalıdır).
Bir Build System ile bütünleşme
Birim testleri normal inşa edilmeli ve normal inşa sürecinin bir parçası olarak çalıştırılmalıdır. CMake, özel bir hedef ekleyebilirsiniz:
add_executable(test_runner test/test_math.c)
target_link_libraries(test_runner ${PROJECT_NAME}_lib)
add_test(NAME test_math COMMAND test_runner)
Sonra, çalışan makine için testlere ihtiyaç duyuyorsunuz. Bu yaklaşım, GitHub Actions veya GitLab CI gibi CI platformlarıyla bütünleşiyor. gömülü projeler için testlere ve sonra bunları döngüde bir emülatör veya donanıma çalıştırabilirsiniz.
Etkili Test Vakaları: Arrange-In-Assert
Her birim testi açık üç adımlı bir yapıyı takip etmelidir. Bu model bazen “triple-A” modeli olarak adlandırılır, okumak ve debug'u okumak için kolay test eder.
- [FONT:0)Arrange[[Dönetici: 1. Sezon 1. Bölüm: Değişkenleri, tüm hafızayı, alay beklentileri, küresel durumu (eğer kaçınılmaz olarak) yapılandırın ve giriş verilerini oluşturun.
- [FONT:0)[[[Dönetici:0))[[[Dönetici: 2))
- [FONT:0]Dr.[[Dönetici:0)) - Geri değer, değiştirilmiş devletin veya beklenen etkileşimlerin beklenen sonuçlarıyla eşleşmesini sağlayın.
Unity'yi kullanarak örnek:
#include "unity.h"
#include "math_utils.h"
void setUp(void) {}
void tearDown(void) {}
void test_add_positive_numbers(void) {
// Arrange
int a = 2;
int b = 3;
// Act
int result = add(a, b);
// Assert
TEST_ASSERT_EQUAL_INT(5, result);
}
Test adının [[Döntücü[Döncükler: 1)) olduğunu unutmayın: hemen size senaryonun test edildiğini söyler.|Ahkeşme 7) veya [[DÜyetim:0)
Naming Conventions and Comments
İyi bir test fonksiyonu adı, karmaşık bir dizi takip eder (örneğin 1000 düğümle bağlantılı bir liste inşa), belirli düzenlemenin neden seçileceğini açıklayan kısa bir yorum.
Dayanıklılık için Testler
Isolation, C kodunın en zor kısmıdır, özellikle bağımlılıklar küresel değişkenleri, statik işlevleri veya donanım kayıtlarını içerir. Hedef, test çiftleri (mocks, stubs veya sahteler) ile gerçekleştirilebilir.
Saf Cocking ve Stubbing in Pure C
Bir alay kütüphanesine karşı bağlantı kurmak, bir bağlantı kutusu kullanarak zaman derlemek için yapılabilir. Örneğin, CMocka ile, bir alay işlevi oluşturabilir ve sonra bağlantıyı gerçek yerine kullanmak için talimat verebilir:
int __wrap_send_to_hardware(int data) {
// Record the call and return a predetermined value
check_expected(data);
return mock_type(int);
}
Sonra, testin eklenebilirliğini bağlantıya bağlandığında, çiftleri test etmek için eklediğiniz makaleye eklediğinizde (Dönder) aşağıdaki tabloda yer alan gerçekleştirilmiş durumda.
Global State ile anlaşma
Global devlet, mümkün olduğunda, kodunuzu bağlam yapıları aracılığıyla geçiş yapmak için yeniden teşvik eder.Eğer küreseller kaçınılmazsa, kullanımÖRT:14 ve [[DÜDÜNT:15) değerlerini kurtarmak ve geri yüklemek için. Bazı çerçeveler (örneğin Check) her testi doğal olarak izole edilen bir süreçten ayırır.
Edge Cases ve Hatayı Korumak
Üretim böcekleri genellikle köşelerde lurk: null pointers, boş diziler, sınır değerleri ve hata geri dönüş kodları. Güçlü bir test paketi, kodu bu eyaletlere kasıtlı olarak kullanan testleri içerecektir.
C Fonksiyonlar için Ortak Edge Vakaları
- [FONT:0]Null pointers[[Döncüler 1 ) – işlev kaza mı geri dönüyor?
- [FONT:0]Zero-uzun uzun sürtücüler[[Dön 1: 1] – fonksiyon boyut 0 girişleri halledebilir mi?
- [0]Maximum ve minimum tamsayı değerleri[Dönetici: 1 ) – Overflow, underflow, imza / imzalanmış konular.
- [FONT:0]Memory tahsis başarısızlıkları[[Dönetici: 1 ) – Özel bir allocator veya alay kullanarak başarısız bir şekilde başarısız bir şekilde yapılır.
- [FONT:0]Dönergesel koşullar[[Dönemli: 1 ) – Tam 0 iterasyon, tam olarak 1 iterasyon, en yüksek izin verilen not say.
- [FONT:0)Error alt temel işlevlerinden kodlar[Dönetici: · 18) geri döndü: [FONT:0], [[FONTD:0) kısmi bir sayı geri döner.
İşte Unity ile bir kenar davası test örneği:
void test_parse_config_null_path(void) {
// Arrange
const char* path = NULL;
// Act
ConfigResult result = parse_config(path);
// Assert
TEST_ASSERT_EQUAL(CONFIG_ERR_NULL_POINTER, result.error);
}
“normal” girişlerin her zaman kullanılacak olduğunu varsaymayın. Açık mutlu yollar, geniş bir hata koşullarını kapsayan daha az değerlidir.
Testlerinizi bir CI Boru Hattında Automating Your Tests in a CI pipeline
Birim testleri her iş üzerinde otomatik olarak çalıştırıldığında en etkilidir. Sürekli entegrasyon (CI) geri dönüşümlerin dakikalar içinde yakalanmasını sağlar, günler değil. C projeleri için, CI'yi açık kaynak araçları ile ayarlaması basit.
Örnek: GitHub Actions with CMake
Bir dosya oluşturun:
name: C Unit Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: sudo apt-get install -y cmake gcc lcov
- name: Configure and build
run: |
mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Debug -DENABLE_TESTS=ON
make
- name: Run tests
run: cd build && ctest --output-on-failure
- name: Generate coverage report
run: cd build && lcov --capture --directory . --output-file coverage.info && genhtml coverage.info --output-dir coverage
Bu iş akışı projeyi derliyor, CTest ile ünite testleri yürütüyor ve bir kod kapsama raporu üretebilir. Daha sonra bir sanat eseri olarak kapsama alanınızı sağlayabilirsiniz.CI entegrasyonunda kapsamlı bir rehber için, ESFLT:0)GitHub Actions belgeleri C/C++).
Test Suitenizi korumak ve Evolving Your Test Suite
Kodbase büyüdükçe, testler mevcut tutulmalıdır. Her zaman geç veya güncel olmayan testler gürültü ve erode güven haline gelmez. test paketinizin değerli kalmasını sağlamak için bu uygulamaları takip edin:
- [FONT:0]Her iş yapmadan önce test eder.[*D:0] Bir ön eş veya CI kapısını mümkün olursa kullanın.
- [FONT:0]Treat test kodu üretim kodu olarak kabul edilir.[DD: 1) Aynı kodlama standartlarını uygulayın, füzyondan kaçınır ve gerektiğinde yeniden faktör.
- [FONT:0)Measure code kapsama alanı[Dönetici: %45) ve [FONT=0) ile birlikte yapılan ölçümler, doğrulanmış davranışlar değil,% 100 satır kapsama alanı (yüzde 70) test kalitesi için iyi bir göstergedir.
- [FONT:0)Ruthlessly ölü test vakalarını sildirir.[DÜT:1] Bir işlev kaldırıldıysa, testleri de kaldırılmalıdır.
- [FONT:0) Yeni özellikler için teste dayalı geliştirme (TDD) kullanılmaktadır.[###0}Önce testi yaz, başarısız olduğunu görün, sonra kod yazmadan önce API sözleşmesini düşünmeniz için minimum kodu uygulayın.
Ortak Pitfalls ve Them'dan Nasıl Kaçırmak
1. Test Order Bağımlılıklara Göre
Mutable global durumu paylaşan testler genellikle belirli bir sırayla çalıştırıldığında geçer, ancak izolasyonda tükenir. Bunu tekrar tanımlamak için küresel durumu 03: 00) veya çatal kullanan bir çerçeve kullanarak kaçının.
2. Davranış Detaylarının Davranışı Yerine Test Etmek
İç veri yapıları veya özel işlevlerin arama testleri kırılgan hale getirir. İçleri yeniden şekillendirmek bir kabus haline gelir çünkü testler kamu davranışının değişmemiş olmasına rağmen kırılır.
3. Hafıza Leakslerini görmezden gelir
C programları hafıza dinamik olarak ve birim testleri de hafızayı sızdırabilir. Valgrind veya adres sanitizer ([DÜ: 4 ) test sırasında CMocka hafıza sızıntılarını otomatik olarak bildirebilir.
4. OverMocking
Her işlev bir alay olduğunda, sadece alayların çağrıldığını test edersiniz, gerçek davranışlar değil. Mock sadece dış bağımlılıklar (file I/O, donanım, ağ).
5. Her iki Debug ve Yayın Bayrakları ile Test Değil
Compiler optimizasyonları böcekleri gizleyebilir (örneğin, öngörülemeyen değişkenler, salıvermede sıfır olabilir, ancak salıverilen çöp).En az iki konfigürasyonlu testleri çalıştırın: 03.Bölüm ve [[DövDÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜ
Sonuç Sonuç Sonuç Sonuç Sonuç Sonuç Sonuç Sonuç
C için bir çalışma testi lüks değildir - reaktif bir şekilde şarj edilen bir disiplindir ve kenar davalarını iyice kaplar, C projelerinizi sağlıklı tutarken sağlam bir test paketi oluşturabilirsiniz. Uygun bir test çerçevesi seçerek, test kodunuzu ürünle yapılandırın.
Küçük başlayın, bugün kodbase'deki en kritik işlevi için bir test yazın. Sonra oradan inşa edin.