<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                # 練習30:自動化測試 > 原文:[Exercise 30: Automated Testing](http://c.learncodethehardway.org/book/ex30.html) > 譯者:[飛龍](https://github.com/wizardforcel) 自動化測試經常用于例如Python和Ruby的其它語言,但是很少用于C。一部分原因是自動化加載和測試C的代碼片段具有較高的難度。這一章中,我們會創建一個非常小型的測試“框架”,并且使用你的框架目錄構建測試用例的示例。 我接下來打算使用,并且你會包含進框架目錄的框架,叫做“minunit”,它以[Jera Design](http://www.jera.com/techinfo/jtns/jtn002.html)所編寫的一小段代碼作為開始,之后我擴展了它,就像這樣: ```c #undef NDEBUG #ifndef _minunit_h #define _minunit_h #include <stdio.h> #include <dbg.h> #include <stdlib.h> #define mu_suite_start() char *message = NULL #define mu_assert(test, message) if (!(test)) { log_err(message); return message; } #define mu_run_test(test) debug("\n-----%s", " " #test); \ message = test(); tests_run++; if (message) return message; #define RUN_TESTS(name) int main(int argc, char *argv[]) {\ argc = 1; \ debug("----- RUNNING: %s", argv[0]);\ printf("----\nRUNNING: %s\n", argv[0]);\ char *result = name();\ if (result != 0) {\ printf("FAILED: %s\n", result);\ }\ else {\ printf("ALL TESTS PASSED\n");\ }\ printf("Tests run: %d\n", tests_run);\ exit(result != 0);\ } int tests_run; #endif ``` 原始的內容所剩不多了,現在我使用`dbg.h`宏,并且在模板測試運行器的末尾創建了大量的宏。在這小段代碼中我們創建了整套函數單元測試系統,一旦它結合上shell腳本來運行測試,你可以將其用于你的C代碼。 ## 完成測試框架 為了基礎這個練習,你應該讓你的`src/libex29.c`正常工作,并且完成練習29的附加題,是`ex29.c`加載程序并合理運行。練習29中我這事了一個附加題來使它像單元測試一樣工作,但是現在我打算重新想你展示如何使用`minunit.h`來做這件事。 首先我們需要創建一個簡單的空單元測試,命名為`tests/libex29_tests.c`,在里面輸入: ```c #include "minunit.h" char *test_dlopen() { return NULL; } char *test_functions() { return NULL; } char *test_failures() { return NULL; } char *test_dlclose() { return NULL; } char *all_tests() { mu_suite_start(); mu_run_test(test_dlopen); mu_run_test(test_functions); mu_run_test(test_failures); mu_run_test(test_dlclose); return NULL; } RUN_TESTS(all_tests); ``` 這份代碼展示了`tests/minunit.h`中的`RUN_TESTS`宏,以及如何使用其他的測試運行器宏。我沒有編寫實際的測試函數,所以你只能看到單元測試的結構。我首先會分解這個文件: libex29_tests.c:1 包含`minunit.h`框架。 libex29_tests.c:3-7 第一個測試。測試函數具有固定的結構,它們不帶任何參數并且返回`char *`,成功時為`NULL`。這非常重要,因為其他宏用于向測試運行器返回錯誤信息。 libex29_tests.c:9-25 與第一個測試相似的更多測試。 libex29_tests.c:27 控制其他測試的運行器函數。它和其它測試用例格式一致,但是使用額外的東西來配置。 libex29_tests.c:28 為`mu_suite_start`測試設置一些通用的東西。 libex29_tests.c:30 這就是使用`mu_run_test`返回結果的地方。 libex29_tests.c:35 在你運行所有測試之后,你應該返回`NULL`,就像普通的測試函數一樣。 libex29_tests.c:38 最后需要使用`RUN_TESTS`宏來啟動`main`函數,讓它運行`all_tests`啟動器。 這就是用于運行測試所有代碼了,現在你需要嘗試使它運行在項目框架中。下面是我的執行結果: ```shell not printable ``` 我首先執行`make clean`,之后我運行了構建,它將模板改造為`libYOUR_LIBRARY.a`和`libYOUR_LIBRARY.so`文件。要記住你需要在練習29的附加題中完成它。但如果你沒有完成的話,下面是我所使用的`Makefile`的文件差異: ```diff diff --git a/code/c-skeleton/Makefile b/code/c-skeleton/Makefile index 135d538..21b92bf 100644 --- a/code/c-skeleton/Makefile +++ b/code/c-skeleton/Makefile @@ -9,9 +9,10 @@ TEST_SRC=$(wildcard tests/*_tests.c) TESTS=$(patsubst %.c,%,$(TEST_SRC)) TARGET=build/libYOUR_LIBRARY.a +SO_TARGET=$(patsubst %.a,%.so,$(TARGET)) # The Target Build -all: $(TARGET) tests +all: $(TARGET) $(SO_TARGET) tests dev: CFLAGS=-g -Wall -Isrc -Wall -Wextra $(OPTFLAGS) dev: all @@ -21,6 +22,9 @@ $(TARGET): build $(OBJECTS) ar rcs $@ $(OBJECTS) ranlib $@ +$(SO_TARGET): $(TARGET) $(OBJECTS) + $(CC) -shared -o $@ $(OBJECTS) + build: @mkdir -p build @mkdir -p bin ``` 完成這些改變后,你現在應該能夠構建任何東西,并且你可以最后補完剩余的單元測試函數: ```c #include "minunit.h" #include <dlfcn.h> typedef int (*lib_function)(const char *data); char *lib_file = "build/libYOUR_LIBRARY.so"; void *lib = NULL; int check_function(const char *func_to_run, const char *data, int expected) { lib_function func = dlsym(lib, func_to_run); check(func != NULL, "Did not find %s function in the library %s: %s", func_to_run, lib_file, dlerror()); int rc = func(data); check(rc == expected, "Function %s return %d for data: %s", func_to_run, rc, data); return 1; error: return 0; } char *test_dlopen() { lib = dlopen(lib_file, RTLD_NOW); mu_assert(lib != NULL, "Failed to open the library to test."); return NULL; } char *test_functions() { mu_assert(check_function("print_a_message", "Hello", 0), "print_a_message failed."); mu_assert(check_function("uppercase", "Hello", 0), "uppercase failed."); mu_assert(check_function("lowercase", "Hello", 0), "lowercase failed."); return NULL; } char *test_failures() { mu_assert(check_function("fail_on_purpose", "Hello", 1), "fail_on_purpose should fail."); return NULL; } char *test_dlclose() { int rc = dlclose(lib); mu_assert(rc == 0, "Failed to close lib."); return NULL; } char *all_tests() { mu_suite_start(); mu_run_test(test_dlopen); mu_run_test(test_functions); mu_run_test(test_failures); mu_run_test(test_dlclose); return NULL; } RUN_TESTS(all_tests); ``` 我希望你可以弄清楚它都干了什么,因為這里沒有什么新的東西,除了`check_function`函數。這是一個通用的模式,其中我需要重復執行一段代碼,然后通過為之創建宏或函數來使它自動化。這里我打算運行`.so`中所加載的函數,所以我創建了一個小型函數來完成它。 ## 附加題 + 這段代碼能起作用,但是可能有點亂。清理框架目錄,是它包含所有這些文件,但是移除任何和練習29有關的代碼。你應該能夠復制這個目錄并且無需很多編輯操作就能開始新的項目。 + 研究`runtests.sh`,并且查詢有關`bash`語法的資料,來弄懂它的作用。你能夠編寫這個腳本的C版本嗎?
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看