imshota / system_development_project_application_1

講義用
0 stars 0 forks source link

ユニットテスト_first #6

Open imshota opened 3 years ago

imshota commented 3 years ago

演習1 自分のOSSにテストを1つ追加せよ

作業記録

自分の検体であるSQLプログラムのサービステストを追加する。 サービスとしては、以下を想定している。

ユーザからIDとPASSを標準入力として受け取る データベースdata.dbからSQL文 select * from scores where id = ID AND pass = 'PASS' を実行する。

テストとして、以下をインライン

result = sqlite3_step(stmt);
  while (result == SQLITE_ROW)
  {
    int id, score;
    char *ps;
    id = sqlite3_column_int(stmt, 0);
    ps = (char *)sqlite3_column_text(stmt, 1);
    score = sqlite3_column_int(stmt, 2);
    printf("\n");
    printf("Success to Log In\n");
    printf("id = %d, pass = %s, score = %d\n", id, ps, score);
    result = sqlite3_step(stmt);
  }

もしテストが成功すれば、 "Success to Log In" が表示されデータベース内のID, PASS, SCOREを "id = ID, pass = PASS, score = SCORE" の形で出力される。

% gcc -Wall -L/usr/lib/sqlite3 SQLi.c -lsqlite3 -o SQLi
% ./SQLi                                               
students id = 1
password = password
sql statement is "select * from scores where id = 1
 AND pass = 'password
'"

失敗している これはfgetsで改行文字まで読み込んでしまっているのが原因

以下を追加

char *p = strchr(num, '\n'), *q = strchr(pass, '\n');
  if (p)
  {
    *p = '\0';
  }
  if (q)
  {
    *q = '\0';
  }

もう一度テストしてみる

 % gcc -Wall -L/usr/lib/sqlite3 SQLi.c -lsqlite3 -o SQLi
% ./SQLi 
students id = 1
password = password
sql statement is "select * from scores where id = 1 AND pass = 'password'"

Success to Log In
id = 1, pass = password, score = 30

テスト成功である

imshota commented 3 years ago

演習2 テストフレームワークを使って自分のOSSにテストを追加せよ

作業記録

CUnit というテストフレームワークを使う https://ja.osdn.net/projects/cunitforando/

やり方はこのサイトを参考にしました https://www.eureka-moments-blog.com/entry/2019/02/17/181353

この関数をテストする

bool mysanitize(char *s)
{
    if (strchr(s, (int)'-') != NULL || strchr(s, (int)';') != NULL)
    {
        return true;
    }
    return false;
}

テストケースはこのように設定

#include <stdio.h>
#include <stdbool.h>
#include <testRunner.h>
#include "mysanitize.h"

static unsigned int testMysanitize(void);

/** Main function. */
int main(void)
{
    return (int)testRunner(testMysanitize);
}

static unsigned int testMysanitize(void)
{
    bool err;
    char *data;

    data = "testing";
    err = mysanitize(data); // do Test
    TEST_ASSERT_EQUALS(err, false);

    data = "abc;efg";
    err = mysanitize(data); // do Test
    TEST_ASSERT_EQUALS(err, true);

    data = "123 - 456";
    err = mysanitize(data); // do Test
    TEST_ASSERT_EQUALS(err, true);

    data = "test  ;  -";
    err = mysanitize(data); // do Test
    TEST_ASSERT_EQUALS(err, true);

    return 0;
}

実際にテストしてみる。

% make
gcc  -ggdb -Wall -I../../CUnitForAndo/include -I../real/include -I./include -c ./src/mysanitizeTest.c
gcc  -ggdb -Wall  -ggdb -Wall -I../../CUnitForAndo/include -I../real/include -I./include -o ./runExe.exe mysanitize.o mysanitizeTest.o testRunner.o 
% make run
./runExe.exe
OK (4 tests)

無事サニタイズできているらしい。

imshota commented 3 years ago

演習3 テスト駆動開発により自分のOSSに機能を追加せよ

作業記録

テスト駆動開発はスライドの手順通りに行う

  1. 作りたい関数の仕様を決める 関数名 testMysanitize 入力 文字列(char) 出力 文字列(char)

入力文字列の中に';' か '-' があれば、それを空白文字に変える。

  1. テストを書く
    
    % cat mysanitizeTest.c
    #include <stdio.h>
    #include <testRunner.h>
    #include "mysanitize.h"

static unsigned int testMysanitize(void);

/* Main function. / int main(void) { return (int)testRunner(testMysanitize); }

static unsigned int testMysanitize(void) { char ret; char data;

data = "testing";
ret = mysanitize(data); // do Test
TEST_ASSERT_EQUALS(ret, "testing");

data = "abc;efg";
ret = mysanitize(data); // do Test
TEST_ASSERT_EQUALS(ret, "abc efg");

data = "123 - 456";
ret = mysanitize(data); // do Test
TEST_ASSERT_EQUALS(ret, "123   456");

data = "test  sabu;  1-1";
ret = mysanitize(data); // do Test
TEST_ASSERT_EQUALS(ret, "test  sabu   1 1");

return 0;

}


3. テストを動かす→コンパイルが失敗する

% make gcc -ggdb -Wall -ggdb -Wall -I../../CUnitForAndo/include -I../real/include -I./include -o ./runExe.exe mysanitize.o mysanitizeTest.o testRunner.o Undefined symbols for architecture x86_64: "_mysanitize", referenced from: _testMysanitize in mysanitizeTest.o ld: symbol(s) not found for architecture x86_64 collect2: error: ld returned 1 exit status make: *** [runExe.exe] Error 1


4. 実装が空の関数を書く

% cat mysanitize.h

ifndef _PLUSH

define _PLUSH

char mysanitize(char s);

endif

% cat mysanitize.c

include "mysanitize.h"

char mysanitize(char s) { return s; }

5. テストを動かす→テストが失敗する

% make run ./runExe.exe ./src/mysanitizeTest.c:24: error: TestCaseError<0x0d936e35><0x0d936e3d> NG (now 1 ok...) make: *** [run] Error 255

一つ動いているのは、サニタイズをしていないから。

6. 関数を実装する

% cat mysanitize.c

include "mysanitize.h"

include

char mysanitize(char s) { char p = strchr(s, ';'), q = strchr(s, '-'); if (p) { p = ' '; } if (q) { q = ' '; } return s; }

7. テストを動かす→テストが成功する

% make run gcc -ggdb -Wall -I../../CUnitForAndo/include -I../real/include -I./include -c ./src/mysanitizeTest.c In file included from ./src/mysanitizeTest.c:2: ./src/mysanitizeTest.c: In function 'testMysanitize': ./src/mysanitizeTest.c:18:24: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] 18 | TEST_ASSERT_EQUALS((int)ret1, (int)"testing"); | ^ ../../CUnitForAndo/include/testRunner.h:44:29: note: in definition of macro 'TEST_ASSERT_EQUALS' 44 | int assertErrorA = (_a);\ | ^~ ./src/mysanitizeTest.c:18:35: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] 18 | TEST_ASSERT_EQUALS((int)ret1, (int)"testing"); | ^ ../../CUnitForAndo/include/testRunner.h:45:29: note: in definition of macro 'TEST_ASSERT_EQUALS' 45 | int assertErrorB = (_b);\ | ^~ ../../CUnitForAndo/include/testRunner.h:44:28: warning: initialization of 'int' from 'char ' makes integer from pointer without a cast [-Wint-conversion] 44 | int assertErrorA = (_a);\ | ^ ./src/mysanitizeTest.c:23:5: note: in expansion of macro 'TEST_ASSERT_EQUALS' 23 | TEST_ASSERT_EQUALS(ret2, "abc efg"); | ^~~~~~ ../../CUnitForAndo/include/testRunner.h:45:28: warning: initialization of 'int' from 'char ' makes integer from pointer without a cast [-Wint-conversion] 45 | int assertErrorB = (_b);\ | ^ ./src/mysanitizeTest.c:23:5: note: in expansion of macro 'TEST_ASSERT_EQUALS' 23 | TEST_ASSERT_EQUALS(ret2, "abc efg"); | ^~~~~~ ../../CUnitForAndo/include/testRunner.h:44:28: warning: initialization of 'int' from 'char ' makes integer from pointer without a cast [-Wint-conversion] 44 | int assertErrorA = (_a);\ | ^ ./src/mysanitizeTest.c:28:5: note: in expansion of macro 'TEST_ASSERT_EQUALS' 28 | TEST_ASSERT_EQUALS(ret3, "123 456"); | ^~~~~~ ../../CUnitForAndo/include/testRunner.h:45:28: warning: initialization of 'int' from 'char ' makes integer from pointer without a cast [-Wint-conversion] 45 | int assertErrorB = (_b);\ | ^ ./src/mysanitizeTest.c:28:5: note: in expansion of macro 'TEST_ASSERT_EQUALS' 28 | TEST_ASSERT_EQUALS(ret3, "123 456"); | ^~~~~~ ../../CUnitForAndo/include/testRunner.h:44:28: warning: initialization of 'int' from 'char ' makes integer from pointer without a cast [-Wint-conversion] 44 | int assertErrorA = (_a);\ | ^ ./src/mysanitizeTest.c:33:5: note: in expansion of macro 'TEST_ASSERT_EQUALS' 33 | TEST_ASSERT_EQUALS(ret4, "test sabu 1 1"); | ^~~~~~ ../../CUnitForAndo/include/testRunner.h:45:28: warning: initialization of 'int' from 'char ' makes integer from pointer without a cast [-Wint-conversion] 45 | int assertErrorB = (_b);\ | ^ ./src/mysanitizeTest.c:33:5: note: in expansion of macro 'TEST_ASSERT_EQUALS' 33 | TEST_ASSERT_EQUALS(ret4, "test sabu 1 1"); | ^~~~~~ gcc -ggdb -Wall -ggdb -Wall -I../../CUnitForAndo/include -I../real/include -I./include -o ./runExe.exe mysanitize.o mysanitizeTest.o testRunner.o ./runExe.exe ./src/mysanitizeTest.c:18: error: TestCaseError<0xe3ba7628><0x0c05be08> NG (now 0 ok...) make: *** [run] Error 255


...前回通った最初のテストケースも通らなくなってしまった。
よって、自分で確認することにする。

include

include

char mysanitize(char s) { char p = strchr(s, ';'), q = strchr(s, '-'); if (p) { p = ' '; } if (q) { q = ' '; } return s; }

int main(void) { char data1[] = "testing"; char *ret1 = mysanitize(data1); // do Test printf("%s\n", ret1);

char data2[] = "abc;efg"; char *ret2 = mysanitize(data2); // do Test printf("%s\n", ret2);

char data3[] = "123 - 456"; char *ret3 = mysanitize(data3); // do Test printf("%s\n", ret3);

char data4[] = "test sabu; 1-1"; char *ret4 = mysanitize(data4); // do Test printf("%s\n", ret4);

return 0; }


テスト

% ./test.out testing abc efg 123 456 test sabu 1 1


テスト成功している。