CMake: Struktur proyek dengan pengujian unit

146

Saya mencoba menyusun proyek saya untuk menyertakan sumber produksi (dalam srcsubfolder) dan pengujian (dalam testsubfolder). Saya menggunakan CMake untuk membangun ini. Sebagai contoh minimal saya memiliki file berikut:

CMakeLists.txt:

cmake_minimum_required (VERSION 2.8) 
project (TEST) 

add_subdirectory (src) 
add_subdirectory (test) 

src / CMakeLists.txt:

add_executable (demo main.cpp sqr.cpp) 

src / sqr.h

#ifndef SQR_H
#define SQR_H
double sqr(double);    
#endif // SQR_H

src / sqr.cpp

#include "sqr.h"
double sqr(double x) { return x*x; }

src / main.cpp - menggunakan sqr, tidak terlalu penting

test / CMakeLists.txt:

find_package(Boost COMPONENTS system filesystem unit_test_framework REQUIRED)

include_directories (${TEST_SOURCE_DIR}/src) 

ADD_DEFINITIONS(-DBOOST_TEST_DYN_LINK) 

add_executable (test test.cpp ${TEST_SOURCE_DIR}/src/sqr.cpp) 

target_link_libraries(test
                      ${Boost_FILESYSTEM_LIBRARY}
                      ${Boost_SYSTEM_LIBRARY}
                      ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}
                      )

enable_testing()
add_test(MyTest test)

test / test.cpp:

#define BOOST_TEST_MODULE SqrTests
#include <boost/test/unit_test.hpp>

#include "sqr.h"

BOOST_AUTO_TEST_CASE(FailTest)
{
    BOOST_CHECK_EQUAL(5, sqr(2));
}

BOOST_AUTO_TEST_CASE(PassTest)
{
    BOOST_CHECK_EQUAL(4, sqr(2));
}

Beberapa pertanyaan:

  1. Apakah struktur ini masuk akal? Apa praktik terbaik saat menyusun kode ini? (Saya berasal dari C # dan java, dan itu lebih mudah dalam arti)
  2. Saya tidak suka fakta bahwa saya harus mencantumkan semua file dari srcfolder di test/CMakeLists.txtfile tersebut. Jika ini adalah proyek perpustakaan, saya hanya akan menautkan perpustakaan. Apakah ada cara untuk menghindari daftar semua file cpp dari proyek lain?
  3. Apa garis enable_testing()dan add_test(MyTest test)lakukan? Saya belum melihat efek apa pun. Bagaimana cara menjalankan tes dari CMake (atau CTest)?
  4. Sejauh ini saya hanya menjalankan cmake .folder root, tetapi ini membuat kekacauan dengan file sementara di mana-mana. Bagaimana saya bisa mendapatkan hasil kompilasi dalam struktur yang wajar?
Grzenio
sumber
Saya menganggap diri saya seorang pemula CMake, jadi saya tidak tahu apa praktik terbaik yang diterima, tetapi FWIW saya akan membuat perpustakaan "sqr" * yang bergantung pada utama dan pengujian. (* atau moral yang setara
dengannya

Jawaban:

129

Untuk pertanyaan 1 & 2, saya akan merekomendasikan membuat perpustakaan dari file non-tes Anda tidak termasuk main.cpp (dalam hal ini hanya src / sqr.cpp dan src / sqr.h), dan kemudian Anda dapat menghindari daftar (dan yang lebih penting kompilasi ulang) semua sumber dua kali.

Untuk pertanyaan 3, perintah ini menambahkan tes yang disebut "MyTest" yang memanggil "test" yang dapat dieksekusi tanpa argumen apa pun. Namun, karena Anda telah menambahkan perintah ini ke test / CMakeLists.txt dan bukan CMakeLists.txt level teratas, Anda hanya dapat menjalankan pengujian dari dalam subdirektori "test" dari pohon build Anda (coba cd test && ctest -N). Jika Anda ingin pengujian dapat dijalankan dari direktori build level teratas, Anda harus memanggil add_testdari CMakeLists.txt level teratas. Ini juga berarti Anda harus menggunakan bentuk yang lebih bertele-tele add_testkarena exe pengujian Anda tidak ditentukan dalam CMakeLists.txt yang sama

Dalam kasus Anda, karena Anda menjalankan cmake di folder root, pohon build dan pohon sumber Anda adalah satu dan sama. Ini dikenal sebagai build dalam sumber dan tidak ideal, yang mengarah ke pertanyaan 4.

Metode yang disukai untuk membuat pohon pembangunan adalah dengan melakukan pembangunan di luar sumber, yaitu membuat direktori di suatu tempat di luar pohon sumber Anda dan menjalankan cmake dari sana. Bahkan membuat direktori "build" di root proyek Anda dan menjalankannya cmake ..akan menyediakan struktur bersih yang tidak akan mengganggu struktur pohon sumber Anda.

Satu poin terakhir adalah untuk menghindari pemanggilan executable "test" (case-sensitive). Untuk alasannya, lihat jawaban ini .

Untuk mencapai perubahan ini, saya akan melakukan hal berikut:

CMakeLists.txt:

cmake_minimum_required (VERSION 2.8)
project (TEST)
add_subdirectory (src) 
add_subdirectory (test)
enable_testing ()
add_test (NAME MyTest COMMAND Test)


src / CMakeLists.txt:

add_library (Sqr sqr.cpp sqr.h)
add_executable (demo main.cpp)
target_link_libraries (demo Sqr)


test / CMakeLists.txt:

find_package (Boost COMPONENTS system filesystem unit_test_framework REQUIRED)
include_directories (${TEST_SOURCE_DIR}/src
                     ${Boost_INCLUDE_DIRS}
                     )
add_definitions (-DBOOST_TEST_DYN_LINK)
add_executable (Test test.cpp)
target_link_libraries (Test
                       Sqr
                       ${Boost_FILESYSTEM_LIBRARY}
                       ${Boost_SYSTEM_LIBRARY}
                       ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}
                       )
Fraser
sumber
2
Saya baru mengetahui bahwa Anda juga menambahkan file .h ke file CMakeLists.txt yang sesuai. Apakah itu wajib? Dan apa yang akan terjadi jika saya mengabaikannya?
Grzenio
3
@Grzenio Ini hanyalah fitur kenyamanan - fitur ini muncul di IDE seperti MSVC sebagai bagian dari target, tetapi sebaliknya ini tidak berpengaruh.
Fraser
1
Di mana TEST_SOURCE_DIR disetel?
aggsol
6
Ini otomatis disetel oleh CMake saat menelepon project (TEST)- lihat cmake.org/cmake/help/v3.6/variable/PROJECT-NAME_SOURCE_DIR.html
Fraser
> mereka muncul di IDE seperti MSVC sebagai bagian dari target --- MSVC tidak mendukung untuk menandai direktori dengan tajuk sebagai "termasuk direktori"?
isnullxbh
48

Saya suka contoh @Fraser tetapi akan menggunakan perintah add_test di test / CMakeLists.txt dan menggunakan enable_testing sebelum add_subdirectory (test).

Dengan cara ini Anda dapat menjalankan pengujian dari direktori build level teratas sambil menentukan pengujian Anda di test / CMakeLists.txt.

Hasilnya akan terlihat seperti ini (saya menggunakan kembali contoh @Fraser):

CMakeLists.txt

cmake_minimum_required (VERSION 2.8)
project (TEST)
add_subdirectory (src)

enable_testing ()
add_subdirectory (test)

src / CMakeLists.txt

add_library (Sqr sqr.cpp sqr.h)
add_executable (demo main.cpp)
target_link_libraries (demo Sqr)

test / CMakeLists.txt

find_package (Boost COMPONENTS system filesystem unit_test_framework REQUIRED)
include_directories (${TEST_SOURCE_DIR}/src
                     ${Boost_INCLUDE_DIRS}
                     )
add_definitions (-DBOOST_TEST_DYN_LINK)
add_executable (Test test.cpp)
target_link_libraries (Test
                       Sqr
                       ${Boost_FILESYSTEM_LIBRARY}
                       ${Boost_SYSTEM_LIBRARY}
                       ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}
                       )
add_test (NAME MyTest COMMAND Test)
Mathias
sumber
1
Terima kasih, saya tidak menunjukkan tes melalui ctest -Nsampai tip Anda tentang mengaktifkan pengujian sebelum menambahkan subdir.
alaferg
@alaferg: jika tidak, mereka akan berakhir di subdirektori pengujian di dalam direktori build.
gauteh
5
Saya berharap CMake memiliki sesuatu yang menyerupai struktur.
ruipacheco