[PYTHON] Eine Geschichte über den Versuch, den Testprozess eines 20 Jahre alten Systems in C zu verbessern

Einführung

Vor einiger Zeit habe ich 20 Jahre lang versucht, verschiedene Tests eines in C-Sprache geschriebenen Systems zu verbessern, daher werde ich ein wenig Wissen schreiben, das ich zu diesem Zeitpunkt habe.

  • Vorsicht Da ich auf meinem eigenen Computer eine Umgebung erstelle, während ich mich an diese Tage erinnere, um Artikel zu schreiben, unterscheidet sie sich tatsächlich von der Umgebung und Version, die ich in der Praxis erstellt habe. Es gibt auch Code in diesem Artikel, aber es ist alles nur ein falsches Beispiel, an das ich gedacht habe, um den Artikel zu schreiben.

Testcode für Unit-Tests erstellen

Mit einem System, das seit 20 Jahren läuft, weiß niemand mehr, was es bedeutet, aber es gibt eine Reihe von Stellen, an denen das vorhandene Verhalten nicht geändert werden sollte.

Wenn Sie keine andere Wahl haben, als an einem solchen Teil zu arbeiten, sind die folgenden Methoden wirksam.

Schreiben Sie zunächst den Testcode für den vorhandenen Code. Und nachdem wir bestätigt haben, dass alle erfolgreich sind, werden wir die Funktion nach und nach erweitern. Auf diese Weise können Sie mit der Funktionsaddition fortfahren und gleichzeitig bestätigen, dass die neue Funktionsaddition die vorhandene Funktion nicht beeinträchtigt.

Es ist ein sogenannter ** Test zuerst **, aber in einer so konservativen Umgebung mit einer langen Geschichte führt das, was Sie in XP gesagt haben, zu verschiedenen Verzerrungen. Wir werden am Ende dieses Kapitels darüber sprechen.

Einführung von xUnit

Sie können Ihr Bestes mit Assert usw. geben, aber es ist besser, ein xUnit-Testframework wie CUnit zu verwenden.

** Cutter ** (1.2.7 veröffentlicht am 13.09.2019 ist das neueste) https://cutter.osdn.jp/index.html.ja

** UNITY ** (v2.4.3 veröffentlicht im November 2017. Einige Commit-Historien sind 2019/10) http://www.throwtheswitch.org/unity https://github.com/ThrowTheSwitch/Unity

Es kann auch aus xUnit-Frameworks für C ++ wie CPPUnit getestet werden, diesmal wird es jedoch entfernt.

Warum benötigen Sie ein xUnit-Testframework?

Es ist besser, ein bekanntes Test-Framework zu verwenden, da es weltweit viele Beispiele für die Realisierung gibt und es bei Problemen hilfreich sein wird. Die Verwendung des bekannten Testframeworks erleichtert außerdem die Arbeit mit Jenkins.

Das [xUnit-Plugin] von Jenkins (https://wiki.jenkins.io/display/JENKINS/xUnit+Plugin) verfügt beispielsweise über eine Funktion zum Aggregieren der XML-Ausgabe des berühmten xUnit und ist einfach automatisch zu testen. Es ist möglich, die Ergebnisse von zu aggregieren.

CUnit CUnit ist ein Framework der xUnit for C-Sprache, das von gcc und visual c verwendet werden kann.

Wie man mit Visual Studio 2019 baut

Da es nur Lösungen aus den Epochen VS2008 und 2005 gibt, ist es alt und es werden Warnungen ausgegeben.

  1. Öffnen Sie CUnit-2.1-3 / VC9 / CUnit.sln
  2. Erstellen Sie CUnit.h basierend auf CUnit-2.1-3 / CUnit / Headers / CUnit.h.in. Die Unterschiede sind wie folgt. image.png
  3. Erstellen Sie in der Reihenfolge libcunit-> andere Projekte.

** So überprüfen Sie die Anzahl der gleichzeitigen Builds eines Projekts in Visual Stduio 2019 ** Wählen Sie "Extras" -> "Optionen" aus dem Menü, um den Optionsdialog zu öffnen, und wählen Sie "Projekte und Lösungen" -> "Erstellen / Ausführen", um den entsprechenden Bildschirm anzuzeigen. image.png

So erstellen Sie mit dem Befehl make

Das folgende Beispiel zeigt das Erstellen mit dem Befehl make unter der Umgebung von Windows 10 + Ubuntu 18.04. Sie können es grundsätzlich auf die gleiche Weise wie im folgenden Artikel erstellen, die Version ist jedoch 2.1-3.

** Unit Test des C-Programms mit CUnit ** https://qiita.com/muniere/items/ff9a984ed7e51eee7112

wget https://jaist.dl.sourceforge.net/project/cunit/CUnit/2.1-3/CUnit-2.1-3.tar.bz2
tar xvf CUnit-2.1-3.tar.bz2
cd CUnit-2.1-3
aclocal
autoconf
automake
./configure
make
make install
Fehlerbehebung
Kein Befehl automake oder autoconf

Führen Sie zur Installation Folgendes aus.

sudo apt-get install autoconf              
Wenn ich configure oder etwas ausführe, erhalte ich den Fehler "configure: error: install-sh, install.sh oder shtool kann in". "" ./ .. "" ./../ .. "" nicht gefunden werden.

Führen Sie den folgenden Befehl aus und beginnen Sie von vorne

autoreconf -i
"Fehler: Libtool-Bibliothek verwendet, aber 'LIBTOOL' ist undefiniert" ist während der Konfiguration aufgetreten

Installieren Sie libtool mit dem folgenden Befehl.

sudo apt-get install libtool
Wenn zur Laufzeit "Fehler beim Laden gemeinsam genutzter Bibliotheken: libcunit.so.1: freigegebene Objektdatei kann nicht geöffnet werden: Keine solche Datei oder kein solches Verzeichnis" angezeigt wird

Legen Sie die Umgebungsvariable LD_LIBRARY_PATH fest.

export LD_LIBRARY_PATH=/usr/local/lib

Wenn Sie es dauerhaft machen möchten, schreiben Sie es in .bashrc

Ausführungsbeispiel

Bei der Ausführung über die Konsole ist dies wie folgt.

#include <CUnit/CUnit.h>

int max(int x, int y) {
	if (x>y) {
		return x;
	} else {
		return y;
	}
}
int min(int x, int y) {
	/** bug  **/
	if (x>y) {
		return x;
	} else {
		return y;
	}
}

void test_max_001(void) {
	CU_ASSERT_EQUAL(max(5, 4) , 5);
}
void test_max_002(void) {
	CU_ASSERT_EQUAL(max(4, 5) , 5);
}
void test_max_003(void) {
	CU_ASSERT_EQUAL(max(5, 5) , 5);
}
void test_min_001(void) {
	CU_ASSERT_EQUAL(min(5, 4) , 4);
}
void test_min_002(void) {
	CU_ASSERT_EQUAL(min(4, 5) , 4);
}
void test_min_003(void) {
	CU_ASSERT_EQUAL(min(5, 5) , 5);
}

int main() {
	CU_pSuite max_suite, min_suite;

	CU_initialize_registry();
	max_suite = CU_add_suite("max", NULL, NULL);
	CU_add_test(max_suite, "test_001", test_max_001);
	CU_add_test(max_suite, "test_002", test_max_002);
	CU_add_test(max_suite, "test_003", test_max_003);

	min_suite = CU_add_suite("min", NULL, NULL);
	CU_add_test(min_suite, "test_001", test_min_001);
	CU_add_test(min_suite, "test_002", test_min_002);
	CU_add_test(min_suite, "test_003", test_min_003);
	CU_console_run_tests();
	CU_cleanup_registry();

	return(0);
}

Weitere Funktionen für ASSERT finden Sie weiter unten. http://cunit.sourceforge.net/doc/writing_tests.html

Bitte verlinken Sie auf libcunit.a, wenn Sie die Quelle kompilieren, auf der CUnit ausgeführt wird.

gcc unit.c  -Wall -L/usr/local/lib -lcunit -o unit

Bei der Ausführung über die Konsole ist dies wie folgt. image.png

Wie man mit Jenkins arbeitet

Erfahren Sie, wie Sie CUnit-Ergebnisse in Jenkins übertragen.

XML im Testcode ausgeben

Ändern Sie den Code, um eine XML-Datei zu erstellen, die an Jenkins übergeben werden soll. Verwenden Sie bei der Ausgabe in eine XML-Datei CU_automated_run_tests und CU_list_tests_to_file anstelle von CU_console_run_tests.

/**Abkürzung**/
	/**Konsolenausgabe
	CU_console_run_tests();
	*/
	/**XML-Ausgabe**/
	CU_set_output_filename("./unit");
	CU_automated_run_tests();
	CU_list_tests_to_file();
	CU_cleanup_registry();
/**Abkürzung**/

Wenn Sie die obige Datei ändern, kompilieren und ausführen, wird die folgende XML-Datei erstellt, anstatt sie an die Konsole auszugeben.

Weitere Informationen zum Ausführen von CUnit finden Sie weiter unten. http://cunit.sourceforge.net/doc/running_tests.html#overview

Lassen Sie Jenkins das XML-Testergebnis analysieren.

Installieren Sie xUnit Plugin in der Plugin-Verwaltung. image.png

Fügen Sie in den Jobeinstellungen dem Post-Build-Prozess "xUnit-Testergebnisbericht veröffentlichen" hinzu und wählen Sie CUnit-2.1 aus.

image.png

Geben Sie unit-Results.xml für Pattern an.

Wenn Sie den Build ausführen, erhalten Sie das folgende Ergebnis: image.png

image.png

Teststubs erstellen

Wenn Sie bei der Automatisierung von Tests nur das xUnit-Testframework ** vorbereiten und versuchen, es zu automatisieren, schlägt die Einführung häufig fehl. Entweder können Sie nur einfache Dienstprogrammfunktionen testen und sie sind veraltet, oder Sie schreiben am Ende komplexen Testcode, um die abhängigen Bibliotheken konsistent zu machen.

Angenommen, Sie haben eine Bibliothek 2, die von Bibliothek 1 abhängt (siehe unten). image.png

Erstellen Sie beim Testen der Bibliothek 2 einen Stub zum Testen der Bibliothek 1, damit geeignete Daten zum Testen der Bibliothek 2 zurückgegeben werden. Selbst wenn Bibliothek 1 vom Netzwerk und der Datenbank abhängt, können Sie sie auf diese Weise in einen geeigneten Testzustand versetzen, ohne sie tatsächlich zu verwenden. image.png

Beispiel für die Erstellung eines einfachen Stubs

Überlegen Sie anhand eines einfachen Beispiels, wie Sie einen Test für Bibliothek 2 schreiben, der von Bibliothek 1 abhängt.

Beispiel für Bibliothek 1

Bibliothek 1 hat die folgende Implementierung. Bereiten Sie eine Funktion namens add vor, die zwei Argumente akzeptiert und das Ergebnis des Hinzufügens zurückgibt.

static1.h


#ifndef STATIC1_H
#define STATIC1_H
extern int add(int x, int y);
#endif

static1.c


#include "static1.h"

int add(int x, int y) {
	return x + y;
}
Beispiel für Bibliothek 2

Bibliothek 2 hat die folgende Implementierung. In Bibliothek 2 wird die Verarbeitung unter Verwendung der Add-Funktion von Bibliothek 1 in der proc-Funktion durchgeführt.

static2.h


#ifndef STATIC2_H
#define STATIC2_H

#include "static1.h"

extern int proc(int x, int y, int z);

#endif

static2.h


#include "static2.h"

int proc(int x, int y, int z) {
	int a = add(x,y);
	return add(a, z);
}
Bibliothek 1 Stub

Erstellen Sie einen Stub anstelle von echtem Code. Die Verarbeitung dieses Stubs führt bei jeder Ausführung der Add-Funktion die folgende Verarbeitung durch. ・ Notieren Sie die Anzahl der Anrufe -Ausführung der im Testcode vorab registrierten Rückruffunktion

stub_static.h


#ifndef STUB_static1_H
#define STUB_static1_H
#include "static1.h"

typedef int (*pfunc_add_def) ( int x , int y );

typedef struct {

    int count_add;
    pfunc_add_def pfunc_add;
} stub_data_def_static1;
extern stub_data_def_static1 stub_data_static1;
#endif

stub_static.c


#include "stub_static1.h"
stub_data_def_static1 stub_data_static1;


int add ( int x , int y ) {
    ++stub_data_static1.count_add;
    
    return stub_data_static1.pfunc_add( x , y );
    
}

Beispiel für einen Testcode

Das Folgende ist ein Beispiel für die Ausführung der proc-Funktion durch Definieren der Rückruffunktion, die vom Stub der add-Funktion im Testcode ausgeführt wird.

#include <CUnit/CUnit.h>
#include "static2.h"
#include "stub_static1.h"

int test001_stub_add(int x, int y) {
	/** add()Stub. X und y zum Testen mit CUNIT**/
	if (stub_data_static1.count_add == 1) {
		/**Erster Aufruf**/
		CU_ASSERT_EQUAL(x , 10);
		CU_ASSERT_EQUAL(y , 5);
		return 15;
	}
	if (stub_data_static1.count_add == 2) {
		CU_ASSERT_EQUAL(x , 15);
		CU_ASSERT_EQUAL(y , 4);
		return 19;
	}
	CU_FAIL("Falsche Anrufanzahl von add");
	return -1;
}

void test001() {
	memset(&stub_data_static1, 0, sizeof(stub_data_static1));
	stub_data_static1.pfunc_add = test001_stub_add;
	int ret = proc(10, 5,4);
	
	/**Überprüfen Sie die Anzahl der Anrufe**/
	CU_ASSERT_EQUAL(stub_data_static1.count_add , 2);
	
	CU_ASSERT_EQUAL(ret , 19);
}


int main() {
	CU_pSuite suite;

	CU_initialize_registry();
	suite = CU_add_suite("stubsample", NULL, NULL);
	CU_add_test(suite, "test001", test001);
	CU_console_run_tests();
	CU_cleanup_registry();

	return(0);
}

Wenn die Stub-Funktion mehrmals aufgerufen wird, überprüfen Sie den Wert des Arguments, das der Stub erhält, basierend auf der Anzahl der Aufrufe, um den Wert zu bestimmen, den der Stub zurückgeben soll.

Automatische Erstellung von Stubs

Im vorherigen Abschnitt haben wir ein Beispiel für einen einfachen Testcode mit Stubs vorgestellt. Das nächste Problem sind die Kosten für die Erstellung von Stubs.

Es ist nicht unmöglich, es von Hand zu erstellen, aber wenn es in Bibliothek 1 eine große Anzahl von Funktionen gibt oder wenn sie häufig aktualisiert werden, kann es schwierig sein, sie von Hand zu ändern. Überlegen wir uns also, wie Stubs automatisch generiert werden.

Es ist im Grunde eine einfache Konvertierung. Daher kann jede Programmiersprache automatisch Stubs generieren. Wenn Sie jedoch Spaß haben möchten, wird eine Programmiersprache empfohlen, die die Vorlagenbibliothek und den C-Sprachparser verwenden kann.

Versuchen Sie, Stubs automatisch mit Python zu generieren

C-Sprachparser-Bibliothek

Sie können C / C ++ - Quellcode mithilfe von pycparser analysieren. https://github.com/eliben/pycparser

Beachten Sie, dass diese Bibliothek nur für Code funktioniert, der vom Präprozessor verarbeitet wurde. Verwenden Sie daher tatsächlich das Ergebnis der Ausführung des Präprozessors wie unten gezeigt für den zu analysierenden Quellcode.

gcc -E static1.h

Dieses Mal werden wir die vorkompilierte Header-Datei wie folgt analysieren.

Zu analysierende Header-Datei


extern int add(int x, int y);
typedef struct {
 int x;
 int y;
} in_data_t;
typedef struct {
 int add;
 int minus;
} out_data_t;
extern void calc(in_data_t* i, out_data_t *o);
extern int max(int data[], int length);

Beispiel zum Analysieren der Header-Datei


import sys
from pycparser import c_parser, c_ast, parse_file

# https://github.com/eliben/pycparser/blob/master/examples/cdecl.py
def _explain_type(decl):
    """ Recursively explains a type decl node
    """
    typ = type(decl)

    if typ == c_ast.TypeDecl:
        quals = ' '.join(decl.quals) + ' ' if decl.quals else ''
        return quals + _explain_type(decl.type)
    elif typ == c_ast.Typename or typ == c_ast.Decl:
        return _explain_type(decl.type)
    elif typ == c_ast.IdentifierType:
        return ' '.join(decl.names)
    elif typ == c_ast.PtrDecl:
        quals = ' '.join(decl.quals) + ' ' if decl.quals else ''
        return quals + _explain_type(decl.type) + '*'
    elif typ == c_ast.ArrayDecl:
        arr = 'array'
        if decl.dim: 
            arr = '[%s]' % decl.dim.value
        else:
            arr = '[]'

        return _explain_type(decl.type) + arr

    elif typ == c_ast.FuncDecl:
        if decl.args:
            params = [_explain_type(param) for param in decl.args.params]
            args = ', '.join(params)
        else:
            args = ''

        return ('function(%s) returning ' % (args) +
                _explain_type(decl.type))

    elif typ == c_ast.Struct:
        decls = [_explain_decl_node(mem_decl) for mem_decl in decl.decls]
        members = ', '.join(decls)

        return ('struct%s ' % (' ' + decl.name if decl.name else '') +
                ('containing {%s}' % members if members else ''))

def show_func_defs(filename):
    # Note that cpp is used. Provide a path to your own cpp or
    # make sure one exists in PATH.
    ast = parse_file(filename, use_cpp=False,
                     cpp_args=r'-Iutils/fake_libc_include')
    if not isinstance(ast, c_ast.FileAST):
        return

    for ext in ast.ext:
        if type(ext.type) == c_ast.FuncDecl:
            print(f"function name: {ext.name} -----------------------")
            args = ''
            print("parameters----------------------------------------")
            if ext.type.args:
                for arg in ext.type.args:
                    print(f"{_explain_type(arg)} {arg.name}")
            print("return----------------------------------------")
            print(_explain_type(ext.type.type))

if __name__ == "__main__":
    if len(sys.argv) > 1:
        filename  = sys.argv[1]
    else:
        exit(-1)

    show_func_defs(filename)

Als einfacher Ablauf des Analyseprozesses kann FileAST als Ausführungsergebnis von parse_file abgerufen werden. Durch Analysieren der ext-Eigenschaft dort können Sie die Informationen der in der Datei definierten Funktion abrufen. Das Ergebnis der Ausführung des obigen Programms und der Überprüfung der Funktionsdefinition in der Header-Datei wird wie folgt ausgegeben.

C:\dev\python3\cparse>python test.py static1.h
function name: add -----------------------
parameters----------------------------------------
int x
int y
return----------------------------------------
int
function name: calc -----------------------
parameters----------------------------------------
in_data_t* i
out_data_t* o
return----------------------------------------
void
function name: max -----------------------
parameters----------------------------------------
int[] data
int length
return----------------------------------------
int

Es wurde bestätigt, dass die C-Sprachquelldatei mit pycparser auf diese Weise leicht analysiert werden kann.

Vorlagenbibliothek

Beim Erstellen von Header- und Quelldateien für Stubs erleichtert die Vorlagenbibliothek das Erstellen. Die Vorlagenbibliothek in Python finden Sie im Folgenden.

** Ich möchte zum ersten Mal seit einiger Zeit HTML in Python ausgeben. Überprüfen Sie daher die Vorlage ** https://qiita.com/mima_ita/items/5405109b3b9e2db42332

Diesmal benutze ich Jinja2.

Code zum Erstellen von Stubs

Im Folgenden finden Sie ein Beispiel für die Implementierung eines Tools zur Stub-Erstellung mithilfe eines Parsers und einer Vorlagenbibliothek in C-Sprache.

create_stub.py


import sys
import os
from pycparser import c_parser, c_ast, parse_file
from jinja2 import Template, Environment, FileSystemLoader


stub_header_tpl = """
#ifndef STUB_{{name}}_H
#define STUB_{{name}}_H
#include "{{name}}.h"
{% for func in function_list %}
typedef {{func.return_type}} (*pfunc_{{func.name}}_def) ({% for arg in func.args %}{% if loop.index != 1 %},{% endif %} {{arg.typedef}} {{arg.name}}{{arg.array}} {% endfor %});
{% endfor %}

typedef struct {
{% for func in function_list %}
    int count_{{func.name}};
    pfunc_{{func.name}}_def pfunc_{{func.name}};
{% endfor %}
} stub_data_def_{{name}};
extern stub_data_def_{{name}} stub_data_{{name}};
#endif
"""

stub_source_tpl = """
#include "stub_{{name}}.h"
stub_data_def_{{name}} stub_data_{{name}};

{% for func in function_list %}
{{func.return_type}} {{func.name}} ({% for arg in func.args %}{% if loop.index != 1 %},{% endif %} {{arg.typedef}} {{arg.name}}{{arg.array}} {% endfor %}) {
    ++stub_data_{{name}}.count_{{func.name}};
    {% if func.return_type != "void" %}
    return stub_data_{{name}}.pfunc_{{func.name}}({% for arg in func.args %}{% if loop.index != 1 %},{% endif %} {{arg.name}} {% endfor %});
    {% else %}
    stub_data_{{name}}.pfunc_{{func.name}}({% for arg in func.args %}{% if loop.index != 1 %},{% endif %} {{arg.name}} {% endfor %});
    {% endif %}
}
{% endfor %}
"""


class ParameterData():
    def __init__(self, name, typedef):
        self.__name = name
        self.__typedef = typedef
        self.__array = ""
        if '[' in typedef:
            self.__array = "[" + typedef[typedef.index("[")+1:typedef.rindex("]")] + "]"
            self.__typedef = typedef[0: typedef.index("[")]

    @property
    def name(self):
        return self.__name

    @property
    def typedef(self):
        return self.__typedef

    @property
    def array(self):
        return self.__array

class FunctionData:
    def __init__(self, name, return_type):
        self.__name = name
        self.__return_type = return_type
        self.__args = []

    @property
    def name(self):
        return self.__name

    @property
    def return_type(self):
        return self.__return_type

    @property
    def args(self):
        return self.__args


# https://github.com/eliben/pycparser/blob/master/examples/cdecl.py
def _explain_type(decl):
    """ Recursively explains a type decl node
    """
    typ = type(decl)

    if typ == c_ast.TypeDecl:
        quals = ' '.join(decl.quals) + ' ' if decl.quals else ''
        return quals + _explain_type(decl.type)
    elif typ == c_ast.Typename or typ == c_ast.Decl:
        return _explain_type(decl.type)
    elif typ == c_ast.IdentifierType:
        return ' '.join(decl.names)
    elif typ == c_ast.PtrDecl:
        quals = ' '.join(decl.quals) + ' ' if decl.quals else ''
        return quals + _explain_type(decl.type) + '*'
    elif typ == c_ast.ArrayDecl:
        arr = 'array'
        if decl.dim: 
            arr = '[%s]' % decl.dim.value
        else:
            arr = '[]'

        return _explain_type(decl.type) + arr

    elif typ == c_ast.FuncDecl:
        if decl.args:
            params = [_explain_type(param) for param in decl.args.params]
            args = ', '.join(params)
        else:
            args = ''

        return ('function(%s) returning ' % (args) +
                _explain_type(decl.type))

    elif typ == c_ast.Struct:
        decls = [_explain_decl_node(mem_decl) for mem_decl in decl.decls]
        members = ', '.join(decls)

        return ('struct%s ' % (' ' + decl.name if decl.name else '') +
                ('containing {%s}' % members if members else ''))

def analyze_func(filename):
    ast = parse_file(filename, use_cpp=False,
                     cpp_args=r'-Iutils/fake_libc_include')
    if not isinstance(ast, c_ast.FileAST):
        return []
    function_list = []
    for ext in ast.ext:
        if type(ext.type) != c_ast.FuncDecl:
            continue
        func = FunctionData(ext.name,  _explain_type(ext.type.type))
        if ext.type.args:
            for arg in ext.type.args:
                param = ParameterData(arg.name, _explain_type(arg))
                func.args.append(param)
        function_list.append(func)
    return function_list


if __name__ == "__main__":
    if len(sys.argv) != 3:
        print("python create_stub.py vorverarbeiteter Header-Ausgabeordner")
        exit(-1)
    filename  = sys.argv[1]
    dst_folder  = sys.argv[2]
    function_list = analyze_func(filename)
    if len(function_list) == 0:
        print("Die Funktion konnte nicht gefunden werden")
        exit(-1)
    data = {
        'name' : os.path.splitext(filename)[0],
        'function_list' : function_list
    }
    #Erstellen einer Stub-Header-Datei
    with open(f"{dst_folder}/stub_{data['name']}.h", mode='w', encoding='utf8') as f:
        f.write(Template(stub_header_tpl).render(data))

    #Erstellen einer Stub-Quelldatei
    with open(f"{dst_folder}/stub_{data['name']}.c", mode='w', encoding='utf8') as f:
        f.write(Template(stub_source_tpl).render(data))

Die mit diesem Tool erstellten Stubs lauten wie folgt.

stub_static1.h



#ifndef STUB_static1_H
#define STUB_static1_H
#include "static1.h"

typedef int (*pfunc_add_def) ( int x , int y );

typedef void (*pfunc_calc_def) ( in_data_t* i , out_data_t* o );

typedef int (*pfunc_max_def) ( int data[] , int length );


typedef struct {

    int count_add;
    pfunc_add_def pfunc_add;

    int count_calc;
    pfunc_calc_def pfunc_calc;

    int count_max;
    pfunc_max_def pfunc_max;

} stub_data_def_static1;
extern stub_data_def_static1 stub_data_static1;
#endif

stub_static.c



#include "stub_static1.h"
stub_data_def_static1 stub_data_static1;


int add ( int x , int y ) {
    ++stub_data_static1.count_add;
    
    return stub_data_static1.pfunc_add( x , y );
    
}

void calc ( in_data_t* i , out_data_t* o ) {
    ++stub_data_static1.count_calc;
    
    stub_data_static1.pfunc_calc( i , o );
    
}

int max ( int data[] , int length ) {
    ++stub_data_static1.count_max;
    
    return stub_data_static1.pfunc_max( data , length );
    
}

Wenn der C-Sprachparser nicht verfügbar ist

Es gibt häufig Situationen, in denen Python nicht verfügbar ist oder der C-Sprachparser nicht verfügbar ist. Verwenden Sie in diesem Fall doxygen.

Doxygen kann die Quelldatei analysieren und die Funktionsinformationen in XML ausgeben. Es ist auch möglich, eine Datei für Stubs basierend auf dieser XML zu erstellen. Viele C- und C ++ - Sites verwenden Sauerstoff, daher ist dies wahrscheinlich ein geringeres Hindernis für die Einführung als die Verwendung von Python. * *

Wie man andere Stubs erstellt und verspottet

Ich habe es nicht wirklich benutzt, aber es gibt andere Methoden wie folgt.

CMock https://github.com/ThrowTheSwitch/CMock Es scheint Code für Mock mit Ruby zu erstellen. Möglicherweise kann Ruby in der Umgebung verwendet werden.

** Ideen zur Verwendung von Stub-Funktionen in C-Sprachtests ** https://qiita.com/HAMADA_Hiroshi/items/e1dd3257573ea466d169 "So führen Sie einen Komponententest durch, indem Sie Funktionen in derselben Quelle stubben, ohne die vorhandene Quelle zu ändern", Grundidee Verwendet Makros, um vorhandene Funktionen durch Aliase zu ersetzen. Glücklicherweise musste ich keinen Test schreiben, um eine Funktion in derselben Quelle aufzurufen, also habe ich sie nicht wirklich verwendet.

Messmethode für die Abdeckungsrate

Wenn Sie einen Testcode schreiben, können Sie beurteilen, ob der Test ausnahmslos ausgeführt wird, indem Sie das vom Testcode abgedeckte Verhältnis messen. Glücklicherweise wird gcc mit einem Tool namens gcov geliefert, mit dem die Abdeckung gemessen werden kann.

10 gcov—a Test Coverage Program https://gcc.gnu.org/onlinedocs/gcc/Gcov.html

** Wie man gcov benutzt ** https://mametter.hatenablog.com/entry/20090721/p1

Beispiel für die Messung der Abdeckung

Messen wir die Abdeckung am Beispiel des zuvor verwendeten Stubs. Ändern Sie diesmal static2.c von Bibliothek 2 wie folgt, um absichtlich eine nicht erreichbare Route zu erstellen.

static2.c


#include "static2.h"

int proc(int x, int y, int z) {
	int a = add(x,y);
	return add(a, z);
}

int proc2() {
	/**Nicht erreicht**/
	return 0;
}

Kompilieren Sie dann mit der Option -coverage, um die Abdeckung zu messen.

gcc -c -Wall -Wextra static2.c -coverage
ar r libstatic2.a static2.o 
gcc -c -Wall -Wextra stub_static1.c
ar r libstub_static1.a stub_static1.o
gcc test.c -coverage  -Wall -Wextra -L. -lstatic2 -lstub_static1   -L/usr/local/lib -lcunit -o test

Durch Ausführen des obigen Befehls werden die folgenden Dateien erstellt.

Danach werden beim Ausführen von test die folgenden Dateien erstellt.

Führen Sie den folgenden Befehl aus, um die Abdeckung von static2.c im Test zu überprüfen.

gcov static2.gcda 

Wenn dieser Befehl ausgeführt wird, wird die folgende Meldung angezeigt.

File 'static2.c'
Lines executed:60.00% of 5
Creating 'static2.c.gcov'

Hier können Sie sehen, dass die Abdeckung 60% beträgt. Um herauszufinden, wo sie nicht abgedeckt ist, zeigen Sie static2.c.gcov an. In diesem Beispiel können Sie sehen, dass proc2 nicht übergeben wird. image.png

Andere automatische Tests

Über den Effekt

Wir beurteilen, dass es in den folgenden Punkten wirksam ist.

・ Das Risiko einer Funktionserweiterung ohne Änderung des Verhaltens der aktuellen Funktion kann unterdrückt werden.

Es gibt jedoch einige Probleme. Betrachten wir sie daher im nächsten Abschnitt.

Was ist mit der SQL-Prüfung?

In einer älteren Umgebung müssen Sie möglicherweise SQL in den Quellcode schreiben und es tatsächlich mit einer Datenbank verbinden und zum Testen ausführen. In diesem Fall ist es wünschenswert, den von jedem Entwickler verwendeten DB-Bereich zu teilen und einen Komponententest durchzuführen.

In einer großen Organisation gibt es jedoch Abteilungen, die sich auf DB spezialisiert haben, und es ist nicht einfach, die Datenbank zu manipulieren. Wenn Sie die Datenbank selbst in die lokale Umgebung stellen, wird ein schlechter PC zu einem Engpass, oder selbst wenn Sie ihn durchbrechen, wenn Sie die Verwaltung der Datenbank in Ihrer persönlichen Umgebung belassen, verwenden einige Entwickler weiterhin die alte Umgebung. Es besteht auch die Gefahr, dass dies geschieht.

In einem solchen Fall können Sie mit einer weniger bewussten Methode des Zurückrollens umgehen, wenn der automatische Test beendet ist.

① Starten Sie den automatischen Test ② Starten Sie eine DB-Transaktion ③ Speichern Sie die Testdaten in der DB ④ Führen Sie einen automatischen Test durch ⑤ Überprüfen Sie anhand des Ergebnisses des automatischen Tests, wie sich die Datenbank geändert hat ⑥ DB-Rollback

Diese Methode ist keine perfekte Idee, aber einfach zu implementieren.

Massive Kombinationstests

Wenn Sie den Eingabewert und den erwarteten Wert in das Array von Strukturen schreiben, können Sie viele Tests durchführen. Eine der am häufigsten verwendeten Methoden besteht darin, eine Liste der Ein- und Ausgaben in Excel zu schreiben, sie mit VBA-Makros in ein Array von C-Sprachstrukturen zu konvertieren und in den Testcode zu schreiben.

Verzerrungstest zuerst in einer konservativen Wasserfallumgebung

Wenn die Methode in einer konservativen Wasserfallumgebung verwendet wird, werden nach Abschluss der Implementierung die Testspezifikationen und Checklisten für Komponententests erstellt und getestet. Wenn Sie jedoch als Erstes einen Test durchführen, ist die Implementierung abgeschlossen = der Komponententest ist abgeschlossen, sodass hier Verzerrungen auftreten.

Plan kommt nicht auf die traditionelle Linie

Bei der herkömmlichen Methode wird die Einteilung in drei Schritten beschrieben: Implementierung, Erstellung einer Checkliste für den Komponententest und Implementierung des Komponententests. Und mit einer hoch kontrollierten, vollständigen und perfekten Organisation ist jeder Prozess genau zeitlich abgestimmt.

Wenn Sie zuerst einen Test durchführen, können Sie den Komponententest nicht von der Implementierung trennen, sodass die individuelle Arbeitszeit nicht gemessen werden kann, und Sie werden ihn separat melden.

Unit-Test-Spezifikationen

Es muss entschieden werden, was mit den mit der herkömmlichen Methode erstellten Unit-Test-Spezifikationen und Checklisten geschehen soll. Es wäre schön, wenn wir entscheiden könnten, dass die Codeüberprüfung des Testcodes in Ordnung ist und dass das Produkt des Komponententests der Testcode ist, aber in einer älteren Umgebung sind Dokumente wichtig. In diesem Fall müssen Sie aus dem Testcode eine Testspezifikation oder eine Checkliste erstellen.

Die erste Gegenmaßnahme besteht darin, den Inhalt des Testcodes manuell auf die Checkliste zu übertragen. Das Problem ist, dass der Testcode und die Testspezifikationen nicht mehr synchron sind. Diese Methode ist auch eine sehr schlechte Antwort, die den Vorteil der automatischen Ausführung von Tests beseitigt. Sie wird jedoch häufig angewendet, da dies jeder tun kann, wenn es Zeit braucht.

Die zweite Methode besteht darin, aus dem Kommentar des Testcodes eine Testspezifikation zu generieren. Beschreiben Sie den Inhalt des Tests im Kommentar des Testcodes und fassen Sie die von Doxygen usw. extrahierten Ergebnisse in der Checkliste zusammen. In diesem Fall besteht die Gefahr, dass zwischen dem Kommentar und der tatsächlichen Verarbeitung eine Diskrepanz besteht.

Die dritte Methode besteht darin, Japanisch zu schreiben, das sich nicht seltsam anfühlt, selbst wenn es in die Checkliste für den im Testcode angegebenen Testnamen ausgegeben wird.

	CU_add_test(max_suite, "max(a,b)Um a=5,b=Bestätigen Sie im Fall von 4, dass der Wert von a erhalten wird", test_max_001);

Wenn Sie den Test mit der obigen Beschreibung ausführen, wird Folgendes in die XML-Datei des Testergebnisses ausgegeben. image.png

Geben Sie danach die XML-Checkliste aus und Sie sind fertig. Das Problem bei dieser Methode besteht darin, dass der Inhalt der Checkliste groß wird, da die von CU_ASSERT_EQUAL usw. durchgeführten Prüfinhalte nicht in XML ausgegeben werden.

Die vierte Methode besteht darin, eine Funktion zu erstellen, die CU_ASSERT_EQUAL usw. umschließt, und innerhalb dieser Funktion den Inspektionsinhalt in einer Datei in einer Form auszugeben, die einfach in die Checkliste ausgegeben werden kann.

Unabhängig davon, für welche Methode Sie sich entscheiden, beachten Sie, dass das Festhalten am Dokument problematisch sein kann. → In einer Kultur, die am Schreiben festhält, stellen wir sicher, dass solche Arbeiten in der Schätzung enthalten sind.

Behandlung von Fehlerrutschen in Unit-Tests

Da der Komponententest nach Abschluss der Implementierung abgeschlossen ist, kann der Fehler im Komponententest nicht ausgelöst werden. Eine stark kontrollierte, vollständige und perfekte Organisation kann sich jedoch auf die Anzahl der Unit-Test-Fehler konzentrieren. In diesem Fall wird das Problem, das während der Implementierung aufgetreten ist, angemessen als solcher Fehler behoben.

Die Theorie, die sein sollte, ist zu überzeugen und neue Regeln zu schaffen, aber ich denke, es ist unmöglich, weil die Kultur anders ist.

Die Ziffern der Anzahl der Tests ändern sich, sodass herkömmliche Indikatoren unbrauchbar werden

Die Einführung automatisierter Tests ermöglicht die mechanische Verarbeitung einer großen Anzahl kombinatorischer Tests. Infolgedessen ist die Anzahl der automatisch durchgeführten Tests größer als die Anzahl der nach dem herkömmlichen Verfahren durchgeführten Tests. (Das ist eine Größenordnung)

Bisher betrug die Anzahl der Punkte auf der Checkliste, die höchstens Hunderte betrug, normalerweise eintausend oder zehntausend. Es ist eine Geschichte über "Was ist falsch daran, viele Tests durchzuführen?". Wenn es sich jedoch um eine stark kontrollierte, vollständige und perfekte Organisation handelt, wird sie als Ausreißer behandelt. Passen Sie daher die Granularität entsprechend an und verwenden Sie sie für die Berichterstellung. Möglicherweise muss die Nummer auf diesen Wert eingestellt werden.

Wenn Sie geeignete Maßnahmen ergreifen möchten, empfiehlt es sich außerdem, einen neuen Index als separate Tabelle für den automatischen Test zu erstellen.

Da die Anzahl der Fehler nach dem Integrationstest geringer ist als zuvor, wird er als Ausreißer behandelt.

Wenn Sie einen umfassenden Komponententest durchführen, haben Sie keine Probleme mit dem Integrationstest.

Dies ist ein Problem damit. Nehmen wir zum Beispiel an, Sie hatten in der Vergangenheit Dutzende von Fehlern, aber die Anzahl der Fehler ist fast verschwunden. Wenn Sie sich nur die Zahlen ansehen, müssen Sie sich fragen, ob die Perspektive des Integrationstests falsch ist.

Viele Leute wollen keinen Testcode schreiben

Wie ich unten schrieb, ist es das, was es ist. Lass uns aufgeben.

** Automatisierung von Unit-Tests mit unbewusstem Visual Studio ** https://qiita.com/mima_ita/items/05ce44c3eb1fd6e9dd46

Es ist möglich, die Wirkung des automatischen Tests durch Arbeitskräfte und Qualität zu erklären, ihn in einen Geldbetrag umzuwandeln, ein Gefühl der Krise zu wecken und Lehrmaterialien vorzubereiten, aber ehrlich gesagt ist es eine Kultur, die nicht verstanden werden kann, egal wie viel sich eine solche Geschichte ansammelt. Funktioniert überhaupt nicht ** ** </ font>.

In jeder Organisation gibt es jedoch nur wenige Menschen mit Bestrebungen. Erwarten wir also solche Menschen.

Statische Analyse

Wir haben im vorherigen Abschnitt über automatisierte Tests gesprochen. Schließlich bewegt sich dies nur tatsächlich und überprüft den Bereich, in dem der Testcode geschrieben wurde. In diesem Abschnitt wird beschrieben, wie Sie eine zweifelhafte Implementierung finden, ohne Testcode zu schreiben und auszuführen.

Finden Sie verdächtige Teile mit statischen Analysewerkzeugen

Mit einem statischen Analysewerkzeug ist es möglich, ein Teil mit einer zweifelhaften Implementierung zu erkennen. Teure Tools können effektive Entdeckungen machen, aber Open Source sind auch effektiv genug.

Für die C-Sprache können Sie CppCheck verwenden. http://cppcheck.sourceforge.net/

cppcheck kann unter Windows mit GUI oder unter Linux basierend auf CUI ausgeführt werden.

Verwendung über die Befehlszeile

In diesem Abschnitt wird beschrieben, wie Sie cppcheck in der Umgebung von Windows 10 + Ubuntu 18.04 verwenden.

Installieren Sie es zunächst mit dem folgenden Befehl.

sudo apt-get install cppcheck

Nach Abschluss der Installation wird cppcheck ausgeführt, indem der folgende Befehl ausgeführt wird.

$ cppcheck --enable=all .
Checking cov.c ...
1/7 files checked 14% done
Checking main.c ...
2/7 files checked 28% done
Checking static1.c ...
3/7 files checked 42% done
Checking static2.c ...
4/7 files checked 57% done
Checking stub_static1.c ...
5/7 files checked 71% done
Checking test.c ...
6/7 files checked 85% done
Checking unit.c ...
7/7 files checked 100% done
[cov.c:7]: (style) The function 'bar' is never used.
[static1.c:7]: (style) The function 'calc' is never used.
[static2.c:8]: (style) The function 'proc2' is never used.
(information) Cppcheck cannot find all the include files (use --check-config for details)

Versuchen Sie, cppcheck mit der Windows-Benutzeroberfläche zu verwenden

(1) Bitte laden Sie das Installationsprogramm von der folgenden Seite herunter. http://cppcheck.sourceforge.net/

(2) Starten Sie nach der Installation CppCheck und der folgende Bildschirm wird geöffnet. image.png

(3) Wählen Sie "Datei" -> "Neues Projekt" aus dem Menü. image.png

(4) Legen Sie einen beliebigen Pfad zum Speichern der Projektdatei fest und klicken Sie auf "Speichern". image.png

(5) Das Dialogfeld "Projektdatei" wird geöffnet. Klicken Sie auf die Schaltfläche "Hinzufügen", um den Pfad hinzuzufügen, der die Quelldatei der Sprache C enthält. image.png

image.png

image.png

(6) Klicken Sie im Dialogfeld "Projektdatei" auf OK, und Sie werden gefragt, ob Sie ein Build-Verzeichnis erstellen möchten. Wählen Sie "Ja". image.png

(7) C-Dateien unter dem angegebenen Verzeichnis werden aufgelistet. image.png

(8) Erweitern Sie die Baumstruktur der aufgezählten Dateien, um die Warnungsdetails anzuzeigen. image.png

Zusammenarbeit mit Jenkins

Mit Jenkins 'Cppcheck Plulgin ist es möglich, die CppCheck-Ergebnisse in Jenkins zu aggregieren. https://plugins.jenkins.io/cppcheck

(1) Wählen Sie CppCheck aus und installieren Sie es im Jenkins-Plug-In-Manager. image.png

(2) Führen Sie cppcheck wie folgt aus, um das Ergebnis in XML zu erhalten.

cppcheck --enable=all --xml --xml-version=2 ~/libsample/. 2>cppcheck.xml

(3) Fügen Sie dem Post-Build-Prozess Publsh Cppcheck-Ergebnisse hinzu. image.png

image.png

(4) Wenn Sie den Build ausführen, wird das CppCheck-Element im Ergebnis angezeigt. image.png

image.png

Metriken messen

Die Anzahl der Schritte im Quellcode und die zyklische Komplexität sind einer der Indikatoren für die Vorhersage der Qualität des Quellcodes.

** Zyklomatische Komplexität ** https://ja.wikipedia.org/wiki/%E5%BE%AA%E7%92%B0%E7%9A%84%E8%A4%87%E9%9B%91%E5%BA%A6

Die zirkuläre Komplexität ist einfach umso höher, je mehr Schleifen und Verzweigungen vorhanden sind. Je höher die Komplexität, desto wahrscheinlicher ist es, dass Fehler enthalten sind. Daher kann diese Metrik als Ausgangspunkt für die Fokussierung Ihrer Tests verwendet werden.

Source Monitor Quellmonitor ist eine Quellcodemetrik, die in C ++, C, C #, VB.NET, Java, Delphi und Visual Basic (VB6) geschrieben wurde. Es ist eine freie Software, die messen kann.

(1) Laden Sie es von der folgenden Seite herunter und extrahieren Sie es in einen beliebigen Ordner. http://www.campwoodsw.com/sourcemonitor.html

(2) Wenn Sie die erweiterte Datei SourceMonitor.exe ausführen, wird der folgende Bildschirm angezeigt. Wählen Sie "Quellmonitor starten". image.png

(3) Wählen Sie im Menü die Option [Datei] -> [Neues Projekt], um ein Projekt zu erstellen, in dem Metriken zusammengefasst werden. image.png

(4) Das Dialogfeld "Sprache auswählen" wird geöffnet. Wählen Sie "C" und klicken Sie auf "Weiter". image.png

(5) Geben Sie den Dateinamen der Projektdatei und den Ordner zum Speichern an und klicken Sie auf "Weiter". image.png

(6) Geben Sie den Ordner an, der den zu analysierenden Quellcode enthält, und klicken Sie auf "Weiter". image.png

(7) Wählen Sie eine Option und klicken Sie auf "Weiter". image.png

Möglichkeit Erläuterung
Use Modified Complexity Metrix Die Standardkomplexitätsmetrik wird berechnet, indem die Fälle in jeder switch-Anweisung gezählt werden. Durch Aktivieren der Prüfung wird jedoch jeder switch-Block nur einmal gezählt und jede case-Anweisung wird geändert. Es wird nicht länger zur Komplexität beitragen.
Do not count blank line Ignorieren Sie leere Zeilen, wenn Sie Zeilen zählen.
Ignore Continuous Header and Footer Comments Aktivieren Sie diese Option, wenn Sie aufeinanderfolgende Kommentarzeilen ignorieren möchten, die Informationen wie den Dateiversionsverlauf enthalten, der automatisch von Versionsverwaltungsprogrammen wie CVS und Visual Source Safe generiert wird.

(8) Klicken Sie auf "Weiter". image.png

(9) Wenn Sie UTF8-Dateien einschließen möchten, aktivieren Sie "Parsing von UTF-8-Dateien zulassen" und klicken Sie auf "Weiter". image.png

(10) Klicken Sie auf "Fertig stellen". image.png

(11) Eine Liste der zu messenden Dateien wird angezeigt. Klicken Sie nach der Bestätigung auf OK. image.png

(12) Das Messergebnis wird angezeigt. image.png

Klicken Sie auf die Liste, um eine Liste der Dateien anzuzeigen. image.png image.png

Klicken Sie auf das Element der Datei in der Liste, um die Details anzuzeigen. image.png

Sie können den Inhalt der Datei überprüfen, indem Sie mit der rechten Maustaste auf das Element der Datei in der Liste klicken, um das Kontextmenü anzuzeigen, und "Quelldatei anzeigen" auswählen. image.png image.png

Häufig verwendete Zahlen

Name Erläuterung
Lines Die Anzahl der physischen Zeilen in der Quelldatei. Wenn bei der Projekterstellung "Leerzeile nicht zählen" aktiviert ist, werden Leerzeilen nicht berücksichtigt. Wird verwendet, um eine grobe Skala zu sehen
Max Complexity Zirkuläre Komplexität. Die Behandlung von Fällen in der switch-Klausel ändert sich abhängig davon, ob beim Erstellen eines Projekts "Modified Complexity Metrix verwenden" aktiviert ist oder nicht. Je höher diese Zahl, desto schwieriger ist es zu testen.
Max Depth Maximale Verschachtelungstiefe. Behalten Sie den Code mit tiefer Verschachtelung im Auge, da er in der Regel kompliziert ist
% Comment Prozentsatz der Kommentare. 0%Im Gegenteil, wenn es zu groß ist, sollten Sie es überprüfen.

Finden Sie einen ähnlichen Code

Es ist möglich, den kopierten Code mithilfe der unten eingeführten PMD-CPD zu erkennen.

** Soll ich diese Kopie reparieren? ** https://qiita.com/mima_ita/items/fe1b3443a363e5d90a21

Anders als während der Entwicklung wird es nicht verwendet, um ähnlichen Code zu finden und ihn allgemein zu machen. ** Im Gegensatz zur Entwicklung kann ein bereits in Betrieb befindliches System nicht einfach überarbeitet werden, z. B. durch Standardisierung, selbst wenn der Code kopiert wird. </ font> **

Der Zweck des Erkennens eines Codeklons in einer solchen Situation besteht darin, herauszufinden, ob andere ähnliche Teile korrigiert werden müssen, wenn ein Quellcode geändert wird, z. B. wenn eine Fehlerantwort oder ein Hinzufügen von Funktionen auftritt.

Wenn Sie beispielsweise einen Fehler machen, werden Sie natürlich gefragt: "Ist ein anderer Teil in Ordnung?" Zu diesem Zeitpunkt können Sie betrügen, indem Sie etwas sagen wie "Ich habe das Tool zur Erkennung von Codeklonen verwendet, um ähnliche Teile umfassend zu untersuchen, und bestätigt, dass es kein Problem gab".

Zusammenfassung des statischen Analysetools

Sie können den Code auswerten und herausfinden, wo er behoben werden kann, ohne den Code tatsächlich zu verschieben.

Die Kosten für die Bereitstellung von Testcode in einer konservativen Umgebung können unübersichtlich sein, statische Analysetools können jedoch kostengünstig und von vielen Organisationen verwendet werden.

Geschichte rund um die Testumgebung

Lassen Sie mich Ihnen während des Tests einige Geschichten über die Umwelt erzählen. Da die Geschichte des Integrationstests aus diesem Kapitel hervorgeht, wird sie außerdem zu einem Titelbetrug von "System made in C language".

Trennung der Unit-Test-Umgebung

Es gibt Standorte, an denen die folgende Konfiguration für Komponententests verwendet wird, unabhängig davon, ob es sich um einen Integrationstest handelt, an dem ein anderes System beteiligt ist. image.png

Die schlechten Punkte dieser Konfiguration sind wie folgt. ・ Es kommt häufig vor, dass die Tests, die sich gegenseitig bestehen, einen Einfluss haben und die ursprünglich bestandenen Fälle abgelehnt werden und umgekehrt.

  • Aufgrund der instabilen Situation beim Testen von Einheiten muss die Testumgebung häufig geändert werden, und die Arbeit anderer Entwickler wird jedes Mal unterbrochen.

Mit anderen Worten ist die Testbarkeit extrem schlecht. Aus diesem Grund ist es wünschenswert, für jeden Entwickler eine Testumgebung wie unten gezeigt bis zum Komponententest vorzubereiten.

image.png

Um jedem Entwickler vor langer Zeit eine Testumgebung zu bieten, habe ich vor langer Zeit ein Programm erzwungen, das unter Linux ausgeführt wird und unter Visual C ++ unter Windows ausgeführt wird. Heutzutage können Sie jedoch eine virtuelle Umgebung mit VMWare oder VirtualBox erstellen, daher sollten Sie sie verwenden.

Wenn der Speicher des PCs, der dem Entwickler zur Verfügung gestellt wird, 4 GB beträgt, denke ich, dass ich in der virtuellen Umgebung aufgeben werde.

Apropos Automatisierung von Releases in Testumgebungen

Wenn Sie es in einer Testumgebung freigeben, in der mehrere Personen es berühren können, ist es besser, es so automatisch wie möglich zu gestalten. Um die Auswirkungen auf die Freigabe zu minimieren, sollten Sie die Ausfallzeit der Testumgebung verkürzen oder freigeben, wenn niemand sie verwendet. Dies kann behoben werden, indem der Freigabeprozess für die Testumgebung automatisiert wird.

Durch Aufzeichnen der Freigabe für die Testumgebung ist es auch möglich zu verfolgen, welche Materialrevision zu welchem Zeitpunkt verwendet wurde. Sie müssen sich nicht an ein bestimmtes Tool wie Jenkins halten, sondern können ein Shell-Skript oder eine Batch-Datei verwenden. Es wäre also schön, es automatisch zu machen.

Durch die Verwendung der Technik im folgenden Artikel denke ich außerdem, dass es möglich sein wird, Materialien von Windows mit WinSCP hochzuladen, das Skript dann über TeraTerm auszuführen und das Ergebnis per E-Mail zu senden.

** Ich frage mich, ob es in Ordnung ist, WinSCP zu automatisieren ** https://qiita.com/mima_ita/items/35261ec39c3c587210d8

** Probieren Sie das TeraTerm-Makro aus ** https://qiita.com/mima_ita/items/60c30a28ea64972008f2

** Automatischer Betrieb von Outlook mit unserer PowerShell, die Redmine aufgegeben hat ** https://qiita.com/mima_ita/items/37ab711a571f29346830

Automatisierung der Massendatenerstellung während Integrationstests

Möglicherweise müssen Sie während des Integrationstests eine große Datenmenge erstellen. Aus Sicht des Integrationstests ist es derzeit nicht möglich, die Daten mit SQL in die Datenbank zu fließen, wenn die Aussage vorliegt, dass "die zu verwendenden Daten vom System erstellt werden können".

Um die vom System bereitgestellten Bildschirme zu bedienen und eine große Datenmenge zu registrieren, können Sie die unter "Automatisieren von Windows-Bildschirmvorgängen" unten eingeführte Technik verwenden.

** Ein selbsternanntes IT-Unternehmen ist auf den Markt gekommen, ohne zu viel IT zu verwenden. Ich werde eine Methode zur Automatisierung von Windows vorstellen https://qiita.com/mima_ita/items/453bb6c313e459c44689

Aufgrund der Eigenschaften des zu übernehmenden Werkzeugs und der zu bedienenden Anwendung gibt es jedoch Fälle, in denen Eingabefehler usw. umgangen werden können. Daher ist bei der Übernahme Vorsicht geboten.

Können Sie den Bildschirmbetrieb des Integrationstests nicht automatisieren?

Ich denke, Sie sollten das Ziel aus folgenden Gründen eingrenzen.

  • Aufgrund der Eigenschaften der verwendeten Werkzeuge und der zu bedienenden Anwendung gibt es Fälle, in denen der automatische Betrieb nicht genau dem manuellen Betrieb entspricht. ・ Die Automatisierung des Bildschirmbetriebs ist grundsätzlich instabil
  • Der automatische Betrieb von Bildschirmoperationen erfordert hohe Erstellungskosten.

Wenn ich das mache, werde ich mich auf Bildschirmbetriebstests für Rauchtests und eine große Menge iterativer Verarbeitung konzentrieren (eine große Menge Daten und Lasttests erstellen).

Aufzeichnung der Niederlage

Eine ideale, aber nutzlose Geschichte

Es gibt einige nutzlose Geschichten, die ideal sind, aber nicht als praktische Angelegenheit eingeführt werden können. Hier möchte ich eine so nutzlose Geschichte vorstellen.

Sprechen Sie über die Einführung von Testmanagement-Tools

image.png

image.png

** Über TestLink, ein Tool zum Verwalten des Testprozesses ** https://qiita.com/mima_ita/items/ed56fb1da1e340d397b9

Ich habe solche Dinge seit 10 Jahren an verschiedenen Orten vorgeschlagen, aber im Grunde denke ich, dass es in einer Umgebung wie SIer schwierig ist.

Organisationen, die an diesen Tools interessiert sind, verwenden sie bereits, und diejenigen, die nicht interessiert sind, sind ** nicht wirklich am Testmanagement selbst interessiert **. Was sollten Sie also tun, wenn Sie viel Geld für die Einführung von Tools ausgeben, die wahrscheinlich nicht gewinnen werden? Ich denke, es gibt andere.

Die Geschichte der Einführung eines Bug-Tracking-Systems

Durch die Einführung eines Fehlerverfolgungssystems können Sie den Verlauf von Fehlern verwalten, den Status ermitteln, wer wie viele Fehler aufweist, und die Zuordnung zum Quellcode verwalten.

Leider wurde mir klar, dass es in einigen Situationen besser ist, sich auf die Grundbildung zu konzentrieren, wie zum Beispiel "wie man eine Fehlerabstimmung schreibt", als Zeit mit dieser Theorie zu verbringen.

Ansammlung von durchsuchbarem Wissen durch Wiki

In Anbetracht der Durchsuchbarkeit und der Aufbewahrung des Verlaufs ist es vorzuziehen, Wiki zu verwenden, anstatt Wissen in Office-Sätzen zu sammeln.

Viele IT-Ingenieure in bestimmten Umgebungen haben jedoch nur Excel zum Schreiben von Sätzen verwendet. Übertreiben Sie es also nicht.

Das nächstbeste, worüber man vergeblich sprechen kann

In dem Bereich, in dem alle oben genannten idealen Geschichten verschwendet werden, werden Testspezifikationen, Fehlermanagementformulare und Wissenssätze in Excel oder Word geschrieben und in einem freigegebenen Ordner verwaltet.

Hierbei gibt es zwei Probleme. Das erste ist das Problem der Durchsuchbarkeit Das zweite ist das Problem der Konfigurationsverwaltung.

Überlegen Sie, wie Sie mit diesen Problemen umgehen sollen.

Suchbarkeitsprobleme

Sie können mit einer kostenlosen Software nach Office-Texten suchen. Wenn überhaupt, können Sie es mit VBS usw. erstellen.

Darüber hinaus denke ich, dass die Suche in Office einige Zeit in Anspruch nimmt. Wenn möglich, wird es meiner Meinung nach nicht stressig sein, Software zu verwenden, die Cache verwendet.

Konfigurationsverwaltungsprobleme

Dateien, die zufällig in einem freigegebenen Ordner abgelegt werden, sind nicht bekannt, wann, wer oder welche Änderungen vorgenommen wurden. Außerdem verschwindet es selten aufgrund eines fehlerhaften Betriebs.

Verwenden Sie als Antwort Konfigurationsverwaltungstools anstelle von freigegebenen Ordnern, um Ihre Dokumente zu verwalten.

Wenn das Konfigurationsmanagement-Tool nicht eingeführt werden kann, lesen Sie bitte Plan B anhand des folgenden Artikels.

** Was tun, wenn Sie in einer Welt wiedergeboren werden, die von gemeinsamem Ordnerunterricht dominiert wird ** https://qiita.com/mima_ita/items/ef3588df4d65cf68f745

schließlich

Ich stellte die Ergebnisse vor, die ich aus dem Versuch gewonnen habe, den Testprozess in einem konservativen Umfeld im Laufe der Jahre zu verbessern. Wie ich im folgenden Artikel geschrieben habe, ist es insbesondere bei dem Versuch, ein konservatives Umfeld zu verbessern, das viele Jahre vergangen ist, notwendig, die aktuelle Situation zu akzeptieren und einen realistischen Landepunkt zu finden.

  • [Wie ich meine Gedanken vorschlage](https://needtec.sakura.ne.jp/wod07672/2020/03/29/%e3%81%bc%e3%81%8f%e3%81 % ae% e3% 81% 8b% e3% 82% 93% e3% 81% 8c% e3% 81% 88% e3% 81% 9f% e3% 81% 95% e3% 81% 84% e3% 81% 8d % e3% 82% 87% e3% 83% bc% e3% 81% ae% e6% 8f% 90% e6% a1% 88% e6% 96% b9% e6% b3% 95 /)

Zunächst die Zeile selbst mit der Aufschrift "Verbessern wir den Testprozess".

image.png

Es ist unvermeidlich, eine solche Reaktion zu erhalten, daher denke ich, dass es schön wäre, wenn sie akzeptiert würde.

Recommended Posts