C++ unit testing & CI integration in GitHub (I/2)
I am working on a side project, Vulkan-Android, that is based on Java, JNI, C++, and Vulkan for Android platform. It also uses my C++ math library. Therefore, the requirement of my build and unit tests are around C++. First of all, I would make sure the unit tests in local are run properly.
C++ unit test on Mac OS
On Mac OS, I think the most convenient way to do unit testing for C++ is writing XCT in Xcode. In the beginning, we need to create a test plan in Xcode. It will helps us create a schema, then, in the test navigator, create a new Unit Test Target. Due to XCT was originally designed for Objective-C or Swift, if we wanna test our C++ code, we need a workaround by making the file extension name to be *.mm.
And then, write down the unit tests as below:
#import <XCTest/XCTest.h>
#include "Vector3d.h"
using namespace gfx_math;
@interface testVector3D : XCTestCase
@end
@implementation testVector3D
- (void)setUp {
// Put setup code here. This method is called before the invocation of each test method in the class.
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
}
- (void)testVectorBasic {
Vector3Df a(1, 0, 0);
float res = a.DotProduct(Vector3Df(1, 0, 0));
XCTAssertEqual(res, 1.0f);
}
@end
Press Cmd + U, Xcode will execute the test plan for you.C++ unit tests with CI
Technically, we should be able to find a CI tool to run these unit tests directly in their service. My first try was Circle-CI, but its Mac OS instance is not free. So, I moved to using GitHub Actions. GitHub has two options for C++ build, one is MS-Build, the other one is Make. I rather chose Make because it is available to run on my Mac OS machine, and if you want, you can integrate it with Google Test as well. As a beginner, I would tend to be not too aggressive, so I used C++ assert() to verify my functions. std::vector<Vector3Df> interPointList;
result = RayIntersectWithSphere(ray, Vector3Df(-10, 0, 0), Vector3Df(0,0,0), 5.0f, interPointList);
assert(result);
assert(interPointList.size() == 2);
Then, create a Makefile like this. We can verify if this Makefile works or not in local first by inserting make clean && make build && ./unittest and submit it to the GitHub repo. In GitHub Actions, choosing create a new workflow with C/C++ with Make, and setup its config file as blow, it will be put under .github/workflows/name: C/C++ CI
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: make clean
run: make clean
- name: make build
run: make build
- name: run unittest
run: ./unittest
This config file will execute a few steps: clean, build, and run the executable file that is our unit tests. After that, every time when committing a new patch to this repo (it could also run besides the master branch?), this workflow will be executed automatically. One last thing, don't forget to add its badge into your README.md file. because it looks really cute.We are also available to use Circle-CI Windows or Linux based Docker images. Although we need to install additional C++ compiler at the beginning, the detail setup and discussion please refer the discussion and the setting.
Android JNI build and testing with CI
For Android projects building in local, it is pretty easy, just run ./gradlew build. Following, in terms of Android C++/JNI testing, I think Google Test is the most convenient one to take. Thanks for AndroidGTestRunner [1] inspires me for doing this. Firstly, we need to add Google Test into our CMakeList build, so pointing to the googletest's CMakeList folder.
add_subdirectory(${THIRD_PARTY_DIR}/googletest gtest).
target_link_libraries(gtest)
For the specific setting, please refer my unittest subfolder. Adding some simple gtest code as below.
TEST(TestVector3D, basic) {
Vector3Df a(1, 0, 0);
float res = a.DotProduct(Vector3Df(1, 0, 0));
ASSERT_EQ(res, 1.0f);
}
GTestRunner is responsible for talking to JNI and collect tests from gtest suite. It helps execute commands via CLI to runner that was built from googletest library.
For launching an Android Emulator in Circle-CI, it is only available to be run on a Mac OS instance and with some complicated setup (I got an another idea by using GitHub Actions when I was writing this post, I will give another post then).
Finally, setup the configuration for Circle-CI workflow.
version: 2.1
orbs:
android: circleci/android@0.2.1
jobs:
build:
executor: android/android
steps:
- checkout
- run: git submodule update --init --recursive
- run:
name: Build unittests
working_directory: ~/project/unittests
command: ./gradlew build
As you can see, the workflow I did is checkout my repo, sync with submodules, and build my project.That is all what I learned about C++ unit testing & CI integration in GitHub, and I will give another post to describe how to setup and run tests on an Android Emulator in GitHub Actions.
[1] AndroidGTestRunner, https://github.com/paleozogt/AndroidGTestRunner
[2] android-studio-googletest, https://github.com/Mr-Goldberg/android-studio-googletest
Comments
Post a Comment