Cicd practice service automatic test

Time:2020-10-26

Introduction

With the development of microservices, containers and cloud computing, more and more concepts such as Devops and CI / CD have come into our eyes in recent years. Many development teams hope to apply these ideas to improve software quality and development efficiency. If a worker wants to do something well, he must first use his tools. What kind of tools can meet the needs of developers? As an excellent open source microservice development and operation integration platform, tars has the characteristics of multi language, high performance, agile R & D and high availability. Can tars support Devops perfectly? stayLastIn this paper, we learned how to integrate the open source CI tool Jenkins with tars to realize the automatic construction and deployment of tars services. Software testing is an essential step in the process of software developmentLastOn the basis of this paper, a complete practice is presented to show how to realize the automatic unit test of tars service through Jenkins and tars integration.

catalog

What is unit testing

Cicd practice service automatic test

With the development of microservices, containers and cloud computing, more and more concepts such as Devops and CI / CD have come into our eyes in recent years. Devs is a continuous software development and testing method that will continue to be used in all software development and testing cycles.

As an excellent open source microservice development and operation integration platform, tars has the characteristics of multi language, high performance, agile R & D and high availability. By integrating the open source CI tool Jenkins with tars, we can realize the automatic testing of tars service development, and reduce the workload of developers and testers. Due to the limited space, this paper only focuses on automated unit testing.

Software testing is an essential step in the process of software development, and unit testing is the most basic form of software testing. In unit test, a unit can refer to a module, a function or a class in the code; unit test is to write test cases for each unit, check the correctness of the unit, test whether the logic is correct, and ensure that the behavior of each unit meets the expectation. Therefore, the addition of unit test can greatly reduce the probability of problems after the software or service goes online.

Environmental preparation

This paper is based on theTarsCppCIDemoProject, use Google test as the unit test framework, in the actual project, please select the test framework according to the requirements.

Install Google test

Google test is a set of open source c + + testing framework of Google, which is convenient for unit testing. Next, we install the framework on the machine where Jenkins is deployed.

The GitHub warehouse address of Google test is:https://github.com/google/googletestCan be directlyclonePost build installation. Here we install the stable version and click on the right side of the GitHub pageReleaseYou can view versions of historical releases. The latest version of this article is1.10.0The download and installation commands are as follows


wget https://github.com/google/googletest/archive/release-1.10.0.tar.gz

tar -zxvf release-1.10.0.tar.gz

cd googletest-release-1.10.0

mkdir build

cd build

cmake ..

make

make install

At this point, Google test is installed.

Unit xplugin installation

XUnit is a Jenkins platform plug-in, which can be used to read unit test results. It supports a variety of test frameworks, including Google test.

Open the Jenkins administration page and enter theSystem Management > plug in Management > optional plug-ins, search in the search boxxUnit, select from the results that appearxUnit plugin, clickDirect installationAfter that, wait for Jenkins to install and restart.

Cicd practice service automatic test

Cicd practice service automatic test

Modify project

Now let’s go back to the demo project we created earlierHelloServerAdd several interfaces and a counting class to implement a simple counting service.

Modification Hello.tars

The interface of the service passes throughtarsFile definition, we editHello.tarsAdd three interfaces to it, namely increase count, decrease count and get current count valueHello.tarsas follows


module TarsCppCIDemo

{

interface Hello

{

int test();

int increment(out int count);

int decrement(out int count);

int getCount(out int count);

};

};

As you can see, in addition to the auto generatedtestInterface, we addedincrement, decrement, getCountThree interfaces, all three interfaces returncountIs the result of the count. In the project rootTarsCppCIDemoEnterHelloServer/srcDirectory, we run scriptstars2cpptakeHello.tarsConvert to the corresponding header fileHello.h


cd HelloServer/src

/usr/local/tars/cpp/tools/tars2cpp Hello.tars

Modify helloimp. H

Then we edit the header file of the interface implementation fileHelloImp.h, in classHelloImpAdd the declaration of three interfaces in the

/**

*@ param count out returns the count value

*@ return service status code

*/

virtual int increment(int& count, tars::TarsCurrentPtr current);

/**

*@ param count out returns the count value

*@ return service status code

*/

virtual int decrement(int& count, tars::TarsCurrentPtr current);

/**

*@ param count out returns the count value

*@ return service status code

*/

virtual int getCount(int& count, tars::TarsCurrentPtr current);

New counter class

Next, let’s build a new oneCounterClass to implement the function of the counter. The singleton class template component is provided in the common component of tarscppTC_Singleton, we inherit the class directly,Counter.hAs follows:

#ifndef __COUNTER_H_

#define __COUNTER_H_

#include "util/tc_singleton.h"

#include "util/tc_thread.h"

#include "util/tc_thread_rwlock.h"

// A simple monotonic counter.

class Counter: public tars::TC_Singleton<Counter> {

private:

int counter_;

tars::TC_ThreadRWLocker rwlocker_;

public:

// Creates a counter that starts at 0.

Counter() : counter_(0) {}

//Returns the count value and performs + 1 on the count

int Increment();

//Returns the count value and performs - 1 on the count

int Decrement();

//Returns the current count value

int GetCount();

};

#endif // __COUNTER_H_

amongTC_ThreadRWLockerFor the tarscpp tool component, more tarscpp common components can be found in theTarsCpp/util/include/utilView its definition and usage in.

Next isCounter.cpp

#include "Counter.h"

int Counter::Increment() {

tars::TC_ThreadWLock wlock(rwlocker_);

return counter_++;

}

int Counter::Decrement() {

if (counter_  ==0) {// is 0

tars::TC_ThreadRLock rlock(rwlocker_);

return counter_;

} else {

tars::TC_ThreadWLock wlock(rwlocker_);

return counter_--;

}

}

int Counter::GetCount() {

tars::TC_ThreadRLock rlock(rwlocker_);

return counter_;

}

That’s itCounterClass is created.

Modification HelloImp.cpp

Next, we add the implementation of the three interfaces


#include "HelloImp.h"

#include "servant/Application.h"

#include "Counter.h"

using namespace std;

void HelloImp::initialize() {

}

void HelloImp::destroy() {

}

int HelloImp::increment(int& count, tars::TarsCurrentPtr current) {

count = Counter::getInstance()->Increment();

return 0;

}

int HelloImp::decrement(int& count, tars::TarsCurrentPtr current) {

count = Counter::getInstance()->Decrement();

return 0;

}

int HelloImp::getCount(int& count, tars::TarsCurrentPtr current) {

count = Counter::getInstance()->GetCount();

return 0;

}

At this point, we have completed the addition of three interface logic.

Establish test project

Next, we create a test project in theHelloServerNew under directorytestTable of contents, andtestChina Newapp_ut.cppandCMakeLists.txtThe directory structure is as follows


HelloServer

├── build

├── CMakeLists.txt

├── src

│   ├── CMakeLists.txt

│   ├── Counter.cpp

│   ├── Counter.h

│   ├── Hello.h

│   ├── HelloImp.cpp

│   ├── HelloImp.h

│   ├── HelloServer.cpp

│   ├── HelloServer.h

│   └── Hello.tars

└── test

├── app_ut.cpp

└── CMakeLists.txt

Add test case

Google test contains rich assertions, which can facilitate unit testing. For the usage of Google test, you can read itWorking with documents

We are hereapp_ut.cppAdd the test process and test cases to theCounterClass adds three test cases, and the execution order of the tests is in the defined order. Among themEXPECT_EQIs an assertion used to determine whether two values are equal. If the two values are not equal, an error is triggered and the output is in the test result.


#define private public

#include "gtest/gtest.h"

#include "Counter.h"

namespace {

// Tests the Increment() method.

TEST(Counter, Increment) {

Counter* c = Counter::getInstance();

EXPECT_EQ(0, c->Increment());

EXPECT_EQ(1, c->Increment());

EXPECT_EQ(2, c->Increment());

EXPECT_EQ(3, c->Increment());

c->counter_ = 0;

}

// Tests the Decrement() method.

TEST(Counter, Decrement) {

Counter* c = Counter::getInstance();

EXPECT_EQ(0, c->Decrement());

EXPECT_EQ(0, c->Increment());

EXPECT_EQ(1, c->Increment());

EXPECT_EQ(2, c->Decrement());

EXPECT_EQ(1, c->Decrement());

c->counter_ = 0;

}

// Tests the GetCount() method.

TEST(Counter, GetCount) {

Counter* c = Counter::getInstance();

EXPECT_EQ(0, c->GetCount());

EXPECT_EQ(0, c->Increment());

EXPECT_EQ(1, c->GetCount());

EXPECT_EQ(1, c->Increment());

EXPECT_EQ(2, c->GetCount());

EXPECT_EQ(2, c->Decrement());

EXPECT_EQ(1, c->GetCount());

c->counter_ = 0;

}

} // namespace

Among them#define private publicIt is a macro replacement commonly used in unit testing, which is convenient to modify private objects for testing.CounterClass is a singleton class. In order not to affect other test cases, each test case willcounter_Zero.

Add to test case CMakeLists.txt

After creating the test case, we need to compile the test project and generate the executable file for the test. The compiler framework can be selected according to your preference. In this example, we use thecmakeManaging code compilation, aboutcmakeYou can refer toOfficial documents

First of all, we are in thetestAdd under directoryCMakeLists.txtThe contents of the document are as follows.


cmake_minimum_required(VERSION 3.10)

find_package(GTest REQUIRED)

set(TARS_INC "/usr/local/tars/cpp/include")

set(TARS_LIB "/usr/local/tars/cpp/lib")

set(TARS_LIB_UTIL "${TARS_LIB}/libtarsutil.a")

set(COUNTER_SRC "${PROJECT_SOURCE_DIR}/src/Counter.cpp")

include_directories(${GTEST_INCLUDE_DIRS}

${TARS_INC}

${PROJECT_SOURCE_DIR}/src )

link_directories(${TARS_LIB})

add_executable(app_ut ${COUNTER_SRC} app_ut.cpp)

target_link_libraries( app_ut

/usr/local/tars/cpp/lib/libtarsutil.a

${GTEST_BOTH_LIBRARIES}

pthread )

gtest_discover_tests(app_ut

XML_OUTPUT_DIR "${PROJECT_SOURCE_DIR}/build/test_result" )

cmakeIn3.10In later versions, thegtestNew support forgtest_discover_testsAdd the test directly, but find the method’sXML_OUTPUT_DIRParameter in3.18Version only works, lower than3.18None of the versions of cannot generate the test results file at the specified path.

Therefore, it is suggested thatcmakeVersion in3.18On the following devices, test cases are run by executing the built test executable file, which will be described in detail in the following sections.

Modify project master CMakeLists.txt

When the tarscpp project generation tool is used to generate a project, theCMakeLists.txt。 Next, we will modify this file to compile test cases while building the project.

In the previous section, we have completed theCMakeLists.txtWrite in the project masterCMakeLists.txtIn the file, just add a subdirectory, as shown belowenable_testing()andadd_subdirectory(test)

cmake_minimum_required(VERSION 2.8.8)

project(Demo-DemoServer)

option(TARS_MYSQL "option for mysql" ON)

option(TARS_SSL "option for ssl" OFF)

option(TARS_HTTP2 "option for http2" OFF)

if(WIN32)

include (c:tarscppmakefiletars-tools.cmake)

else()

include (/usr/local/tars/cpp/makefile/tars-tools.cmake)

endif()

####you can: cd build; cmake .. -DTARS_WEB_HOST={your web host}

set(TARS_WEB_HOST "" CACHE STRING "set web host")

IF (TARS_WEB_HOST STREQUAL "")

set(TARS_WEB_HOST "http://tars.test.com")

ENDIF ()

include_directories(/usr/local/tars/cpp/thirdparty/include)

link_directories(/usr/local/tars/cpp/thirdparty/lib)

#include_directories(/home/tarsprotol/App/OtherServer)

enable_ Testing() ා open test

add_subdirectory(src)

add_ Subdirectory (test) ා add test

#target_link_libraries(mysqlclient ssl crypto nghttp2-static)

Next, compile and build the project according to the compilation method of tarscpp project.

Run test cases

There are two ways to run test cases, one of which can be selected according to the requirements

  • Direct usecmakeIntegrated test function, after the completion of the build, only need tobuildDirect execution under directorymake testThat’s right. RequestcmakeVersion is3.18
  • Run the test case to compile the built executable file. After executing the project build command, thebuild/binIn this project, the test case executable file is generatedapp_utIt is suitable forcmake 2.8.8The above version. Parameters are usually added--gtest_output="xml:test*.xml"Used to output test results, as follows

./bin/app_ut --gtest_output="xml:testresults.xml"

Modify Jenkins project configuration

This section describes how to configure Jenkins tasks to automatically execute unit tests in a project and obtain test results.

Modify build shell command

In the script of the build process, we only need to add the command to run the test case. According to theRun test casesPart, according tocmakeSelect any command for version. Take the executable file of test case as an example. The modified build script is as follows


#!/bin/sh

mkdir -p HelloServer/build

cd HelloServer/build

cmake ..

make -j4

make HelloServer-tar

./bin/app_ut --gtest_output="xml:test_results.xml"

Add post build actions

clickAdd post build operation stepschoicePublish xUnit test result reportAdd the post build steps as follows

Cicd practice service automatic test

And then in theReport Typeclicknewly added, selectGoogleTest

Cicd practice service automatic test

And then in thePatternFill in the matching pattern, which is used to match thexmlFiles, you can use patterns directly**/*.xmlMatch allxmlFile, you can also customize the pattern matching according to the naming method, as follows

Cicd practice service automatic test

Finally, clickpreservationThe Jenkins task is configured.

automated testing

Previously, we have completed the configuration required for automated testing. As with automated build and deployment, we only need to push the project to GitHub repository to trigger the automated build and test process.

After the build is complete, we can view the test results of this build, as follows

Cicd practice service automatic test

Based on our own testing framework of Jenkins, we can complete the test based on our own plug-in.

summary

This paper is in thePrevious articleThis paper introduces how to integrate Jenkins and tars to realize the automatic unit test of tars service, and help to improve the software quality in the process of software development.

Tars can quickly build the system and automatically generate code while considering the ease of use and high performance. It can help developers and enterprises to quickly build their own stable and reliable distributed applications in the way of microservices, so that developers can only focus on business logic and improve operational efficiency. Multi language, agile R & D, high availability and efficient operation make tars an enterprise level product.

Tars microservices help you with digital transformation. Welcome to:

Tars website:https://TarsCloud.org

Tars source code:https://github.com/TarsCloud

Linux foundation official micro service free course:https://www.edx.org/course/bu…

Access to tars official training eBook:https://wj.qq.com/s2/6570357/…

Or scan the code to obtain:

Cicd practice service automatic test