在软件开发过程中,行为驱动开发(BDD)是一种强调软件行为和业务需求的测试方法。它通过使用自然语言来定义测试案例,使得非技术人员也能参与到测试用例的编写中。Gherkin DSL(Domain Specific Language)是BDD中常用的一种语言,它允许开发者以易于理解的格式来描述软件的行为。
当一个现有的项目使用Visual Studio的CppUnitTestFramework进行单元测试时,引入使用Gherkin DSL编写的BDD测试意味着需要切换测试框架并添加其他依赖,如果使用Cucumber-CPP的话。为了简化这个过程,可以编写一个Python 2.7脚本来解析Gherkin特征文件,并生成适用于CppUnitTestFramework的桩代码。
本文将展示如何使用附带的脚本和头文件。读者可以自行修改脚本,以生成他们偏好的测试框架和工作语言的输出。
文件 "example.feature" 包含了使用Gherkin编写的测试用例。
Feature: Accumulator
Background:
Given an initial
Scenario Outline: Add one other
When you add a
Then the result is
Examples:
| value | second | sum |
| 1 | 2 | 3 |
| 2 | 2 | 4 |
Scenario Outline: Add two others
When you add a
And you add a
Then the result is
Examples:
| value | second | third | sum |
| 1 | 2 | 3 | 6 |
| 2 | 3 | 4 | 9 |
运行脚本 "features.py" 将生成以下C++代码:
#include "stdafx.h"
#include "CppUnitTest.h"
#include "TestUtils/LogStream.h"
#include
#include
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
#define AddOneOtherInst(_VALUE, _SECOND, _SUM) \
TEST_METHOD(AddOneOther ## _VALUE ## _SECOND ## _SUM) \
{ \
AddOneOther(#_VALUE, #_SECOND, #_SUM); \
}
#define AddTwoOthersInst(_VALUE, _SECOND, _THIRD, _SUM) \
TEST_METHOD(AddTwoOthers ## _VALUE ## _SECOND ## _THIRD ## _SUM) \
{ \
AddTwoOthers(#_VALUE, #_SECOND, #_THIRD, #_SUM); \
}
namespace Example {
TEST_CLASS(Accumulator) {
static std::streambuf * oldBuffer;
static std::shared_ptr newBuffer;
void GivenAnInitial(std::string value) {
std::clog << "Given an initial " << value << std::endl;
}
void WhenYouAddA(std::string second) {
std::clog << "When you add a " << second << std::endl;
}
void ThenTheResultIs(std::string sum) {
std::clog << "Then the result is " << sum << std::endl;
}
static void AddOneOther(std::string value, std::string second, std::string sum) {
std::clog << "Feature: Accumulator" << std::endl;
std::clog << "Scenario: Add one other" << std::endl;
Accumulator instance;
instance.GivenAnInitial(value);
instance.WhenYouAddA(second);
instance.ThenTheResultIs(sum);
}
static void AddTwoOthers(std::string value, std::string second, std::string third, std::string sum) {
std::clog << "Feature: Accumulator" << std::endl;
std::clog << "Scenario: Add two others" << std::endl;
Accumulator instance;
instance.GivenAnInitial(value);
instance.WhenYouAddA(second);
instance.WhenYouAddA(third);
instance.ThenTheResultIs(sum);
}
TEST_CLASS_INITIALIZE(ClassInitialize) {
newBuffer = std::make_shared();
oldBuffer = std::clog.rdbuf(newBuffer.get());
std::clog << "Entering Example" << std::endl;
}
TEST_CLASS_CLEANUP(ClassCleanup) {
std::clog << "Exiting Example" << std::endl;
std::clog.rdbuf(oldBuffer);
newBuffer = nullptr;
}
public:
AddOneOtherInst(1, 2, 3);
AddOneOtherInst(2, 2, 4);
AddTwoOthersInst(1, 2, 3, 6);
AddTwoOthersInst(2, 3, 4, 9);
};
std::streambuf * Accumulator::oldBuffer = nullptr;
std::shared_ptr Accumulator::newBuffer = nullptr;
}
构建并运行后,将产生以下输出:
------ Run test started ------
Entering Example
Feature: Accumulator
Scenario: Add two others
Given an initial 2
When you add a 3
When you add a 4
Then the result is 9
Feature: Accumulator
Scenario: Add two others
Given an initial 1
When you add a 2
When you add a 3
Then the result is 6
Feature: Accumulator
Scenario: Add one other
Given an initial 2
When you add a 2
Then the result is 4
Feature: Accumulator
Scenario: Add one other
Given an initial 1
When you add a 2
Then the result is 3
Exiting Example
========== Run test finished: 4 run (0:00:00.6816458) ==========
from tests named:
AddOneOther123
AddOneOther224
AddTwoOthers1236
AddTwoOthers2349
在实现脚本之前,测试类只包含静态方法,并且存在大量复制粘贴的情况。现在,测试类继承了基类,以便在基类中编写公共步骤,即测试代码更像它测试的内容。