- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我正在使用 C++ 17 练习排序算法,并按如下方式实现了我的单元测试(以下编译和所有测试都是绿色的):
template <typename T>
class SortingmethodTest : public ::testing::Test
{
protected:
T sortingmethod;
static constexpr int amount_test_data[7] = {0, 4, 8, 10, 256, 1000, 1234};
};
using sortingmethods = ::testing::Types<STLSort<int>,
InsertionSort<int>,
ShellSort<int>,
MergeSort<int>,
OptimizedMergeSort<int>,
QuickSort<int>>;
TYPED_TEST_SUITE(SortingmethodTest, sortingmethods);
TYPED_TEST(SortingmethodTest, sort)
{
for (const auto& amount : this->amount_test_data)
{
Sortvector<int> test(amount);
test.vul_random_zonder_dubbels(); // Fills the vector
this->sortingmethod(test); // operator() of the sortmethod used (STLSort, InsertionSort, ...) sorts the vector
ASSERT_TRUE(test.is_range());
ASSERT_TRUE(test.is_gesorteerd());
ASSERT_TRUE(std::is_sorted(test.begin(), test.end()));
}
}
TYPED_TEST(SortingmethodTest, sort_reverse)
{
// ...
}
TYPED_TEST(SortingmethodTest, sort_already_sorted)
{
// ...
}
TYPED_TEST(SortingmethodTest, sort_empty)
{
// ...
}
我想对除整数以外的其他类型重复相同的测试,例如
STLSort<int>,
InsertionSort<int>,
ShellSort<int>,
MergeSort<int>,
OptimizedMergeSort<int>,
QuickSort<int>
STLSort<double>,
InsertionSort<double>,
ShellSort<double>,
MergeSort<double>,
OptimizedMergeSort<double>,
QuickSort<double>
STLSort<CustomType>,
InsertionSort<CustomType>,
ShellSort<CustomType>,
MergeSort<CustomType>,
OptimizedMergeSort<CustomType>,
QuickSort<CustomType>
...
我如何在 C++ 中使用 google test 尽可能干净地执行此操作并尽可能多地重用?我迷失在类型化测试和类型参数化测试的丛林中 [1]:我什么时候应该使用其中之一?
谨致问候,
貂
[1] https://github.com/google/googletest/blob/master/docs/advanced.md#type-parameterized-tests
最佳答案
令人沮丧的是,到目前为止,googletest API 并没有给我们更多的利用现代 C++ 使测试代码简洁,特别是对于测试模板。但是直到 v1.8.x(当前版本系列在这个日期)googletest 一直致力于 C++98 兼容性,这主要是原因。即将发布的 1.9.x 版本将转向 C++11 兼容性,我们希望以获得更强大的 API。
不过,现在可以编写相当简洁明了的 googletest 代码来做你想做的事:也就是说,单元测试一致模板的不同值只有一个模板参数。
实现它的方法不止一种。这是其中之一的工作示例,使用 type-parameterized tests .
我们将有一组三个模板
template<typename T> struct (AA|BB|CC) {...};
其中每一个都提供(至少)接口(interface):
Name::Name(T const & u);
Name::operator int() const;
Name Name::operator+(Name const & u) const;
Name & Name::operator+=(Name const & u);
Name Name::operator-(Name const & u) const;
Name & Name::operator-=(Name const & u);
Name
= (AA|BB|CC)
.我们想单元测试此接口(interface),针对每个 (AA|BB|CC)
, 每个实例化为六种类型中的每一种:
char, int, float, AA<char>, BB<int>, CC<float>
所以这是要测试的 18 个实例化:
AA<char>, AA<int>, AA<float>, AA<AA<char>>, AA<BB<int>>, AA<CC<float>>
BB<char>, BB<int>, BB<float>, BB<AA<char>>, BB<BB<int>>, BB<CC<float>>
CC<char>, CC<int>, CC<float>, CC<AA<char>>, CC<BB<int>>, CC<CC<float>>
为简短起见,我们将只实现两个通用测试。对于对象 a
, b
和 c
任何实例化测试类型:
a = b + c; b += c
之后, 然后 a == b
.b != c
, 在 a = b - c; c -= b
之后, 然后 a != c
.(至少,只要操作不溢出或失去精度,我会避免这种情况)。
所以我们预计会看到 36 项测试。
对于这个插图,我不关心什么AA
, BB
和 CC
除了它们的通用界面外,所以我只是想从一个模型中导出它们,就像这样:
some_types.h
#pragma once
#include <type_traits>
namespace detail {
template<typename T>
struct bottom_type {
using type = T;
};
template<template<typename ...> class C, typename ...Ts>
struct bottom_type<C<Ts...>> {
using type = typename C<Ts...>::type;
};
}
template<typename T>
using bottom_t = typename detail::bottom_type<T>::type;
template<
typename T,
typename Enable = std::enable_if_t<std::is_arithmetic_v<bottom_t<T>>>
>
struct model
{
using type = bottom_t<T>;
model() = default;
model(model const &) = default;
model(T const & t)
: _t{t}{}
operator type() const { return _t; }
auto operator+(model const & u) const {
return _t + u;
}
auto & operator+=(model const & u) {
_t += u;
return *this;
}
auto operator-(model const & u ) const {
return _t - u;
}
auto & operator-=(model const & u ) {
_t -= u;
return *this;
}
protected:
type _t = 0;
};
template<typename T> struct AA : model<T>{ using model<T>::model; };
template<typename T> struct BB : model<T>{ using model<T>::model; };
template<typename T> struct CC : model<T>{ using model<T>::model; };
现在这是我的 googletest 代码:
main.cpp
#include <array>
#include <algorithm>
#include <random>
#include <type_traits>
#include <limits>
#include <gtest/gtest.h>
#include "some_types.h"
template<typename T>
struct fixture : public ::testing::Test
{
protected:
template<typename U>
static auto const & test_data() {
using type = bottom_t<U>;
static std::array<type,1000> data;
static bool called;
if (!called) {
std::default_random_engine gen;
auto low = std::numeric_limits<type>::min() / 2;
auto high = std::numeric_limits<type>::max() / 2;
auto dist = [&low,&high](){
if constexpr (std::is_floating_point_v<type>) {
return std::uniform_real_distribution<type>(low,high);
} else {
return std::uniform_int_distribution<type>(low,high);
}
}();
std::generate(
data.begin(),data.end(),[&dist,&gen](){ return dist(gen); });
called = true;
}
return data;
}
};
template<template<typename> class C, typename ...Ts>
using test_types = ::testing::Types<C<Ts>...>;
using AA_test_types = test_types<AA,char,int,float,AA<char>,BB<int>,CC<float>>;
using BB_test_types = test_types<BB,char,int,float,AA<char>,BB<int>,CC<float>>;
using CC_test_types = test_types<CC,char,int,float,AA<char>,BB<int>,CC<float>>;
TYPED_TEST_SUITE_P(fixture);
TYPED_TEST_P(fixture, addition)
{
using wrapped_type = typename TypeParam::type;
auto const & data = this->template test_data<wrapped_type>();
auto fi = data.begin(); auto ri = data.rbegin();
for ( ; fi != ri.base(); ++fi, ++ri)
{
TypeParam lhs{*fi}, rhs{*ri};
auto sum = lhs + rhs;
lhs += rhs;
ASSERT_EQ(lhs,sum);
}
}
TYPED_TEST_P(fixture, subtraction)
{
using wrapped_type = typename TypeParam::type;
auto const & data = this->template test_data<wrapped_type>();
auto fi = data.begin(); auto ri = data.rbegin();
for ( ; fi != ri.base(); ++fi, ++ri) {
TypeParam lhs{*fi}, rhs{*ri};
if (lhs != rhs) {
auto diff = lhs - rhs;
rhs -= lhs;
ASSERT_NE(rhs,diff);
}
}
}
REGISTER_TYPED_TEST_SUITE_P(fixture,addition,subtraction);
INSTANTIATE_TYPED_TEST_SUITE_P(AA_tests, fixture, AA_test_types);
INSTANTIATE_TYPED_TEST_SUITE_P(BB_tests, fixture, BB_test_types);
INSTANTIATE_TYPED_TEST_SUITE_P(CC_tests, fixture, CC_test_types);
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
让我们来看看兴趣点:-
template<template<typename> class C, typename ...Ts>
using test_types = ::testing::Types<C<Ts>...>;
在这里,我正在制作 test_types
::testing::Types<SomeType...>
的模板别名列表其中 SomeType
将是被测模板之一的实例化。作为它发生了,我的模板 AA
, BB
, CC
(像你的)都是以下形式:
template<typename T> class;
所以我想要test_types
成为:
::testing::Types<C<Ts>...>
然后我定义了 3 个具体的类型别名:
using AA_test_types = test_types<AA,char,int,float,AA<char>,BB<int>,CC<float>>;
using BB_test_types = test_types<BB,char,int,float,AA<char>,BB<int>,CC<float>>;
using CC_test_types = test_types<CC,char,int,float,AA<char>,BB<int>,CC<float>>;
分别相当于:
::testing::Types<AA<char>, AA<int>, AA<float>, AA<AA<char>>, AA<BB<int>>, AA<CC<float>>>;
::testing::Types<BB<char>, BB<int>, BB<float>, BB<AA<char>>, BB<BB<int>>, BB<CC<float>>>;
::testing::Types<CC<char>, CC<int>, CC<float>, CC<AA<char>>, CC<BB<int>>, CC<CC<float>>>;
然后我用模板夹具 fixture
定义一个类型参数化的测试套件.
TYPED_TEST_SUITE_P(fixture);
然后我定义了我的两个类型参数化测试模式。
TYPED_TEST_P(fixture, addition)
{
using wrapped_type = typename TypeParam::type;
auto const & data = this->template test_data<wrapped_type>();
auto fi = data.begin(); auto ri = data.rbegin();
for ( ; fi != ri.base(); ++fi, ++ri)
{
TypeParam lhs{*fi}, rhs{*ri};
auto sum = lhs + rhs;
lhs += rhs;
ASSERT_EQ(lhs,sum);
}
}
TYPED_TEST_P(fixture, subtraction)
{
using wrapped_type = typename TypeParam::type;
auto const & data = this->template test_data<wrapped_type>();
auto fi = data.begin(); auto ri = data.rbegin();
for ( ; fi != ri.base(); ++fi, ++ri) {
TypeParam lhs{*fi}, rhs{*ri};
if (lhs != rhs) {
auto diff = lhs - rhs;
rhs -= lhs;
ASSERT_NE(rhs,diff);
}
}
}
然后我在每次实例化时注册这两种模式以进行实例化的 fixture
:
REGISTER_TYPED_TEST_SUITE_P(fixture,addition,subtraction);
然后我创建了 3 个名为 (AA|BB|CC)_tests
的实例化的 fixture
为了测试类型列表 (AA|BB|CC)_test_types
分别是:
INSTANTIATE_TYPED_TEST_SUITE_P(AA_tests, fixture, AA_test_types);
INSTANTIATE_TYPED_TEST_SUITE_P(BB_tests, fixture, BB_test_types);
INSTANTIATE_TYPED_TEST_SUITE_P(CC_tests, fixture, CC_test_types);
就是这样。编译链接:
$ g++ -std=c++17 -Wall -Wextra -pedantic -o gtester main.cpp -lgtest -pthread
运行:
./gtester
[==========] Running 36 tests from 18 test suites.
[----------] Global test environment set-up.
[----------] 2 tests from AA_tests/fixture/0, where TypeParam = AA<char>
[ RUN ] AA_tests/fixture/0.addition
[ OK ] AA_tests/fixture/0.addition (0 ms)
[ RUN ] AA_tests/fixture/0.subtraction
[ OK ] AA_tests/fixture/0.subtraction (1 ms)
[----------] 2 tests from AA_tests/fixture/0 (1 ms total)
[----------] 2 tests from AA_tests/fixture/1, where TypeParam = AA<int>
[ RUN ] AA_tests/fixture/1.addition
[ OK ] AA_tests/fixture/1.addition (0 ms)
[ RUN ] AA_tests/fixture/1.subtraction
[ OK ] AA_tests/fixture/1.subtraction (0 ms)
[----------] 2 tests from AA_tests/fixture/1 (0 ms total)
...
...
...
[----------] 2 tests from CC_tests/fixture/4, where TypeParam = CC<BB<int> >
[ RUN ] CC_tests/fixture/4.addition
[ OK ] CC_tests/fixture/4.addition (0 ms)
[ RUN ] CC_tests/fixture/4.subtraction
[ OK ] CC_tests/fixture/4.subtraction (0 ms)
[----------] 2 tests from CC_tests/fixture/4 (0 ms total)
[----------] 2 tests from CC_tests/fixture/5, where TypeParam = CC<CC<float> >
[ RUN ] CC_tests/fixture/5.addition
[ OK ] CC_tests/fixture/5.addition (0 ms)
[ RUN ] CC_tests/fixture/5.subtraction
[ OK ] CC_tests/fixture/5.subtraction (0 ms)
[----------] 2 tests from CC_tests/fixture/5 (0 ms total)
[----------] Global test environment tear-down
[==========] 36 tests from 18 test suites ran. (4 ms total)
[ PASSED ] 36 tests.
关于c++ - 如何在 Google Test 中使用不同模板测试多个模板化类的相同行为?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55892577/
我使用 apt-get install libgtest-dev 安装了 gtest 我正在尝试检查它是否有效。 所以我在 eclipse 中编写了简单的测试代码。 但是有错误, undefined
($test) = (@test); $test = @test; 用一个括号括住变量,它访问数组的第一个元素。我找不到有关数组括号的信息。 最佳答案 ($test) = (@test); 这会将@t
在 clojure.test 中有一个允许同时测试多个设备的宏: are . 在 clojure.test 中,可以结合 are宏与 testing ? IE。就像是: (are [scenario
通常,Rust 中的单元测试被赋予一个单独的模块,该模块使用 #[cfg(test)] 进行条件编译: #[cfg(test)] mod tests { #[test] fn test
在过去,编程很少涉及猜测。我会写几行代码,一眼就能 100% 确定代码做什么和不做什么。错误主要是拼写错误,但与功能无关。 我相信在过去的几年中存在这种“试错”编程的趋势:编写代码(就像在草稿中一样)
在building the Kotlin compiler之后(在提交e80a01a处): ./gradlew dist 测试未成功通过: ./gradlew compiler:test 由于很少有测
关闭。这个问题需要更多focused .它目前不接受答案。 想改进这个问题吗? 更新问题,使其只关注一个问题 editing this post . 关闭 9 年前。 Improve this qu
最近一直在思考模糊测试和猴子测试的区别。根据 wiki,猴子测试似乎“只是”一个单元测试,而模糊测试则不是。安卓有 UI/Application Exerciser monkey而且它看起来不像是单元
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
现在我正在使用 CMake 设置一个 C++ 测试环境。其实我已经意识到我想做什么,但我对两种不同的测试输出风格感到困惑。在我下面的示例中,“make test”实际上做了什么?我认为“make te
在 VS2012 中运行单个测试时,测试资源管理器底部会显示一个窗口,其中包括(假设失败)旁边带有“测试失败”的红色图标。紧随其后的是带有“已用时间”的失败消息。 我想简单地知道是否有办法清除这个窗口
bash 是否可以从 shell 执行命令,如果它返回某个值(或空值)则执行命令? if [ "echo test" == "test"]; then echo "echo test output
这个问题在这里已经有了答案: 8年前关闭。 Possible Duplicate: What is a smoke testing and what will it do for me? 为什么“冒烟
x86 下的并行编程可能很困难,尤其是在多核 CPU 下。假设我们有多核 x86 CPU 和更多不同的多线程通信组合。 单一作者和单一读者 单个读者多个作者 多个读者和单个作者 多个读者和多个作者 那
我使用Ctest来运行一堆使用add_test()注册的Google测试。当前,这些测试没有任何参数。但是,我想在运行--gtest_output=xml时为它们提供所有参数(所有参数都通用,特别是c
我有下表和数据: CREATE TABLE `test` ( `id` int(11) NOT NULL auto_increment, `name` varchar(8) NOT NULL,
go test 的两个标志 -parallel 和 -test.parallel 之间的区别以及哪个标志优先? -parallel n Allow parallel execu
在我的组件 AudioPlayer 中,我有一个 download() 方法: download() { this.audio.pause(); window.open(this.file,
您必须承认,对于 Rails 和数据库的新手来说,rubyonrails.org 上的官方解释使所有这四个任务听起来完全一样。引用: rake db:test:clone Recreate the
我过去曾讨论过这个话题,我想我可能知道答案,但我无法正确地表达出来。 这是我认为我所知道的: 如果您在编写测试之前已经有了关于事情如何工作的想法,那么我怀疑您是测试优先而不是测试驱动,因此您首先编写测
我是一名优秀的程序员,十分优秀!