I recently discover cucumber and I'm really interested in using it as
a framework for BDD for your project. As we develop in C++, I'd like
to know if cucumber can easily work with a C++ based project. If so,
ss there any tutorial or a documentation about using cucumber with C+
+ ?
Cheers,
Jaonary
I'm attempting to do exactly that with cucumber. Here is the approach I'm taking:
Cucumber (to run the scenario files). Using Cuke4Nuke to run step definitions in C#. Using managed C++ to wrap unmanaged C++ classes/functions; using the unmanaged C++ functions to call into a DLL that I've written in C++.
So you have the following setup:
Cuke4Nuke lets you run cucumber, and arranges for cucumber to find step definitions using the "wire" protocol. This setup lets you write your step definitions in C#.
The step definitions in C# use .net objects and methods to execute code. So you can create a .net assembly in C# and test that assembly using cucumber.
Now for the fun part. As far as I know (and this is the point where I'm at now in my investigation) you can call methods on any .net assembly from C#. So the next step is to create a separate assembly in managed C++ which is callable from C#. Within a managed C++ file, you can include unmanaged code. In particular, you can write unmanaged code that makes calls to C++ dlls. So your managed C++ code can make calls (through the unmanaged code) to functions/methods exposed in your DLLs. If your DLL is written in C++, then you can call those c++ methods through mananged code.
And if you can call then through managed C++ code, you should be able to call them through C#; and thus from your step definitions.
I'm pretty close today to putting this all together, and I'll keep you up to date on how things are going.
Hi everybody,
Cheers,
Jaonary
--
You received this message because you are subscribed to the Google Groups "Cukes" group.
To post to this group, send email to cu...@googlegroups.com.
To unsubscribe from this group, send email to cukes+un...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/cukes?hl=en.
For example: http://blog.objectmentor.com/articles/2008/02/04/unit-testing-c-and-c-with-ruby-and-rspec
He is using Swig to connect C/C++ classes to RSpec. You could do
almost the exact same thing for Cucumber step definitions. There are
other approaches that would work too.
How well does swig work with C++ classes? In particular, we pass classes with std::wstring values into our C++ functions.
And is using swig really that easy? Do I need to compile the generated file? Does swig output a build script that can be used in windows, or am I stuck using linux?
Sounds to me like you have a layer in there you don't need. Cuke4Nuke
doesn't care which .NET language you used to create your step
definition DLL, so you can skip C# and write your step definitions in
managed C++ if you like.
Richard
[Note: I've written lots of code in C# and unmanaged C++; but this will be the first time in managed c++. :)
]
-----Original Message-----
From: cu...@googlegroups.com [mailto:cu...@googlegroups.com] On Behalf Of Richard Lawrence
Sent: Wednesday, March 31, 2010 5:32 PM
To: cu...@googlegroups.com
Richard
On Wed, Mar 31, 2010 at 4:39 PM, Robert Hanson
My point (for Jaonary's benefit) was the Swig is a better solution for
a non-Windows environment. If I were working in a .NET environment I
would use Cuke4Nuke as you suggested.
Also, see below:
On Wed, Mar 31, 2010 at 3:23 PM, Robert Hanson
<Robert...@calabrio.com> wrote:
> Thanks Adam. I am indeed running in a windows environment.
>
> How well does swig work with C++ classes? In particular, we pass classes with std::wstring values into our C++ functions.
>
Swig handles standard library strings just fine. I have heard of some
people having problems with template functions in Swig. See here for
more info: http://www.swig.org/index.php
> And is using swig really that easy? Do I need to compile the generated file? Does swig output a build script that can be used in windows, or am I stuck using linux?
>
Relative to working with C/C++ it is pretty easy. Of course you need
to compile the generated interface wrapper (Although, there is no
separate compile step for Ruby code.) Swig does run on Windows, but
see: http://www.swig.org/compat.html
Again, I would probably prefer Cuke4Nuke + managed C++ in a .NET
environment. Cucumber + Swig is a preferred solution for Linux.
cheers,
Matt
I see there are already a lot of good advice further down in this
thread, but I thought I should mention a really interesting piece of
work:
http://github.com/paoloambrosio/spike-cuke4cpp
http://groups.google.com/group/cukes/browse_thread/thread/b7a91149771fd4c3/811d17dbde6143e1
If someone wants to pick up on Paolo's work that would be great.
Regarding the Wire protocol - I've been thinking about adding support
for an additional wire protocol based on Thrift -
http://incubator.apache.org/thrift/
I think using Thrift might make it easier to implement support for new
languages, since a lot of the socket/marshalling plumbing is already
implemented in Thrift (assuming of course that the target language has
a Thrift server side impl).
Aslak
> I think, I'll first take a look at spike-cuke4cpp, it seems to an
> interesting solution to work on both windows and linux.
Hello,
I'm the developer of the cuke4cpp spike solution. Unfortunately the
spike was written primarily to demonstrate that it was possible, so
there are memory leaks and it does not work on Windows because of the
"static initialization order fiasco" [1] (working as a Java developer
I was fooled by it).
I am working on a complete rewrite that I hope to release by the end
of April. At first I tried to understand how to call the steps
directly from Cucumber, without using the wire protocol, but then I
decided to leave it as a future enhancement (I want to be able to
change both the test framework and the Cucumber communication layer,
but the first release will support just GTest and the Wire Protocol).
I haven't published it yet because the classes/structure is still too
dynamic and it won't help contributions. I will write here as soon as
I release it, meaning that it can run the same example as the spike
does. Then I will be gladly accepting contributions ;-)
Paolo
1: http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.12
Great news Paolo. Any thoughts on using Thrift? I think we could
easily support it on the Cucumber (client) side - something I'd gladly
implement if it simplifies the implementation of other "server" side
implementations (like C++).
Aslak
>
> Paolo
>
>
> 1: http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.12
> Great news Paolo. Any thoughts on using Thrift? I think we could
> easily support it on the Cucumber (client) side - something I'd gladly
> implement if it simplifies the implementation of other "server" side
> implementations (like C++).
I have already implemented the socket server and written a small spike
for json serialization, so the first CukeBins release (didn't like the
name cuke4cpp that much) will use the wire protocol.
Having Thrift support won't probably make a difference to me now, but
I think it might be a feature worth considering for the future. It
will be much easier to track protocol changes on the IDL, but I'm
unsure if those would be handled gracefully by Thrift.
Paolo
Feature file looks like this:
Feature: Login to Rascal
In order to test cucumber integration with unmanaged c++
As an investigator
I want to execute the login function for Rascal Client
Scenario: login to Rascal
When I
Then the login should be successful
===========================================================
Steps file (in C++) looks like this
#using <c:\Ruby\lib\ruby\gems\1.8\gems\cuke4nuke-0.3.1\dotnet\Cuke4Nuke.Framework.dll>
#using <c:\Ruby\lib\ruby\gems\1.8\gems\cuke4nuke-0.3.1\dotnet\Cuke4Nuke.TestStepDefinitions.dll>
#using <c:\Program Files\NUnit 2.5.3\bin\net-2.0\framework\nunit.framework.dll>
using namespace NUnit::Framework;
using namespace Cuke4Nuke::Framework;
class RascalLoginSteps
{
public:
int rval;
[When("^I$")]
void I()
{
rval = 0;
}
[Then("^the login should be successful$")]
void IsOnSearchPage()
{
Assert::That(rval == 0);
}
};
============================================================
So I've tried lots of combinations of things, and they always turn out like this:
C:\projects\IppaDotNet>cuke4nuke debug/ippadotnet.dll
Feature: Login to Rascal
In order to test cucumber integration with unmanaged c++
As an investigator
I want to execute the login function for Rascal Client
Scenario: login to Rascal # features\RascalLogin.feature:6
When I # features\RascalLogin.feature:7
Then the login should be successful # features\RascalLogin.feature:8
1 scenario (1 undefined)
2 steps (2 undefined)
0m0.328s
You can implement step definitions for undefined steps with these snippets:
[Pending]
[When(@"^I$")]
public void I()
{
}
[Pending]
[Then(@"^the login should be successful$")]
public void TheLoginShouldBeSuccessful()
{
}
C:\projects\IppaDotNet>
=====================================================================
Any suggestions? I'm wondering if the regular expressions are not written right? And of course, the examples shown by cuke4nuke are for c#, not c++.
At this point in time, the project consists entirely of managed C++ code, in just the one file I've included above. No other sources (managed or unmanaged) are used. The cucumber.wire file is exactly like that of your cuke4nuke example.
===========================================================
============================================================
C:\projects\IppaDotNet>
=====================================================================
2010-04-06 16:27:01,453 [1] INFO Cuke4Nuke.Server.NukeServer - Listening on port 3901
2010-04-06 16:27:01,531 [1] INFO Cuke4Nuke.Server.NukeServer - Waiting for client to connect.
2010-04-06 16:27:05,500 [1] INFO Cuke4Nuke.Server.NukeServer - Connected to client.
2010-04-06 16:27:05,500 [1] INFO Cuke4Nuke.Server.NukeServer - Waiting for request.
2010-04-06 16:27:05,500 [1] INFO Cuke4Nuke.Server.NukeServer - Received request <["begin_scenario"]>.
2010-04-06 16:27:05,718 [1] INFO Cuke4Nuke.Server.NukeServer - Responded with <["success",null]>.
2010-04-06 16:27:05,718 [1] INFO Cuke4Nuke.Server.NukeServer - Waiting for request.
2010-04-06 16:27:05,734 [1] INFO Cuke4Nuke.Server.NukeServer - Received request <["step_matches",{"name_to_match":"I"}]>.
2010-04-06 16:27:05,796 [1] INFO Cuke4Nuke.Server.NukeServer - Responded with <["step_matches",[]]>.
2010-04-06 16:27:05,796 [1] INFO Cuke4Nuke.Server.NukeServer - Waiting for request.
2010-04-06 16:27:05,843 [1] INFO Cuke4Nuke.Server.NukeServer - Received request <["step_matches",{"name_to_match":"the login should be successful"}]>.
2010-04-06 16:27:05,843 [1] INFO Cuke4Nuke.Server.NukeServer - Responded with <["step_matches",[]]>.
2010-04-06 16:27:05,843 [1] INFO Cuke4Nuke.Server.NukeServer - Waiting for request.
2010-04-06 16:27:05,906 [1] INFO Cuke4Nuke.Server.NukeServer - Received request <["end_scenario"]>.
2010-04-06 16:27:05,937 [1] INFO Cuke4Nuke.Server.NukeServer - Responded with <["success",null]>.
2010-04-06 16:27:05,937 [1] INFO Cuke4Nuke.Server.NukeServer - Waiting for request.
2010-04-06 16:27:05,953 [1] INFO Cuke4Nuke.Server.NukeServer - Received request <["snippet_text",{"multiline_arg_class":"","step_keyword":"When","step_name":"I"}]>.
2010-04-06 16:27:05,968 [1] INFO Cuke4Nuke.Server.NukeServer - Responded with <["snippet_text","[Pending]\n[When(@\"^I$\")]\npublic void I()\n{\n}"]>.
2010-04-06 16:27:05,968 [1] INFO Cuke4Nuke.Server.NukeServer - Waiting for request.
2010-04-06 16:27:05,984 [1] INFO Cuke4Nuke.Server.NukeServer - Received request <["snippet_text",{"multiline_arg_class":"","step_keyword":"Then","step_name":"the login should be successful"}]>.
2010-04-06 16:27:05,984 [1] INFO Cuke4Nuke.Server.NukeServer - Responded with <["snippet_text","[Pending]\n[Then(@\"^the login should be successful$\")]\npublic void TheLoginShouldBeSuccessful()\n{\n}"]>.
2010-04-06 16:27:05,984 [1] INFO Cuke4Nuke.Server.NukeServer - Waiting for request.
2010-04-06 16:27:06,015 [1] INFO Cuke4Nuke.Server.NukeServer - Received request <>.
2010-04-06 16:27:06,015 [1] INFO Cuke4Nuke.Server.NukeServer - Client disconnected.
2010-04-06 16:27:06,015 [1] INFO Cuke4Nuke.Server.NukeServer - Waiting for client to connect.
===========================================================
============================================================
C:\projects\IppaDotNet>
=====================================================================
Cuke4Nuke is not finding matching step definitions in your DLL, but I
don't know enough about managed C++ to say why the methods you've
defined wouldn't appear as step definition methods. The regular
expressions look right, I think.
Richard
On Tue, Apr 6, 2010 at 10:10 PM, Robert Hanson
Is the default access for a managed C++ class public?
You can check by using Reflector to browse the exposed types in your assembly.
Fixed it, I think. The C++ class definition has to have "ref" in front of it:
ref class RascalLoginSteps
{
public:
int rval;
[When("^I$")]
void I()
{
rval = 0;
}
[Then("^the login should be successful$")]
void IsOnSearchPage()
{
Assert::That(rval == 0);
}
};
-----Original Message-----
From: Robert Hanson
Sent: Thursday, April 08, 2010 9:29 AM
To: 'cu...@googlegroups.com'
Subject: RE: [Cucumber:4016] Cucumber and C++
OK Richard, I'm going to add some debug msgs to the Cuke4Nuke code to see whats up. I'll let you know what I find.
-----Original Message-----
From: cu...@googlegroups.com [mailto:cu...@googlegroups.com] On Behalf Of Richard Lawrence
Sent: Thursday, April 08, 2010 8:57 AM
Subject: Re: [Cucumber:4016] Cucumber and C++
Fixed it, I think. The C++ class definition has to have "ref" in front of it:
Yes. Without the ref, its not exported (that is, it’s not part of the dll public interface). That’s just one of the things in managed c++ I’m learning about. But that was enough to get my first tests to pass. So now I have cucumber running tests where part of the code is in a dll written with non-managed c++
For those of you keeping score, here is where I’m at so far:
1) You can have some of your step definitions is ruby step definition files; and some in your .net assembly. (the .net assembly is the dll you’ve written in C# or managed C++, which you pass on the command line when you start cuke4nuk). Cucumber looks in both places (the ruby step definition files, and on the wire)
One open question: in pure cucumber, your step definition implementation code can invoke other steps. I’m not sure if the steps in your assembly can invoke other steps, and/or if those steps can be back in the ruby step files. I’ll investigate that soon.
2) your managed c++ classes have to be ref classes, so that they’re exposed on the dll’s public interface. The suggestion to use reflector was REALLY helpful here.
3) When building your managed c++ dll, your step implimentations will be in managed c++. Typically within those steps you’ll be creating instances of your unmanaged c++ classes.
3A) To get the dll to link and run, you need to add the .lib file for your unmanaged dll to the linker settings.
3B) It’s really fun to try to figure out when/where you can use unmanaged instance objects within managed code. Sometimes you have to play a few tricks.
3C) With managed/unmanaged code, it is important to remember that the garbage collector can run and move your objects around. There is an ability to “pin” your objects so they don’t get moved which is important in unmanaged code. I’m still trying to get my hands around this In pure managed code you never have to worry about this.
4) when you start cuke4nuke, the cuke4nuke process loads the managed dll you specified; part of that loading process is to load the other needed dlls (specifically your unmanaged dll) so the directory where that is located needs to be available; one way to do that is to put the path to the dll into your PATH variable.
5) You can add code to your managed dll to log into the cuke4nuke log file. I *think* your’re out of luck within your unmanaged dll through. (and you probably don’t want to pollute your business logic with cucumber stuff anyway).
6) Parameters passed to your method are extracted as System::String; and can be converted by the .net framework to the desired type assuming that the string can be converted:
[Then("^(.*) is logged in.$")]
void IppaLoginSteps::AgentAIsLoggedIn(String ^Id)
{
…
}
[Then("^I see (.*) books.$")]
void IppaLoginSteps::ISeeNBooks(int books)
{
…
}
One open question: in pure cucumber, your step definition implementation code can invoke other steps. I’m not sure if the steps in your assembly can invoke other steps, and/or if those steps can be back in the ruby step files. I’ll investigate that soon.
Hi. I’m working on writing some tests, and have questions on an appropriate way to organize them.
Background: I’m working on a program that runs in call centers. Each call center agent has a program that runs on his desktop (the client); these connect to a central server in a client-server arrangement. I’m testing the server. So in my tests, one or more client programs connect to the server.
So for the first question, I wrote a scenario like this:
Feature: Agents Login to Bippa Server
In order to take calls using the ippa Client
As a agent
I want to login to the Bippa server
<some scenarios removed>
Scenario: multiple agents are logged in at once
Given Agent A is a ippa agent
And Agent B is a ippa agent
And Agent C is a ippa agent
When Agent A logs in to Bippa
When Agent B logs in to Bippa
When Agent C logs in to Bippa
Then Agent A is logged in.
Then Agent B is logged in.
Then Agent C is logged in.
But that is really wordy. What I’d really like to write is something more like a scenario outline:
Given X is a ippa agent
When X logs in to Bippa
Then Agent X is logged in
[list of agents – A, B, C]
But this is not meant as a sequential process (first A is logged in and validated; then B is logged in and validated, etc) but that the 3 agents are logged in; then the 3 agents are validated. This scenario is intended to demonstrate that multiple agents can be logged in at the same time. Any suggestions?
Maybe something like:
Given agents A,B,C
When the agents logs in
Then the agents are logged in
Where the code for the Given step remembers the list of agents, and the remaining steps process those agents?
=======================================================================================
Second question:
In our setup, an agent can be either logged in or logged out; and if logged in, the agent can be in a number of states. So I’ve written a scenario like this:
Scenario: login to Bippa
Given B is a ippa agent
And B is logged in
And B is ready
When …
Then …
This could get wordy. What I’d like to do is the following:
If I say Given B is a ippa agent, that means the agent is just that; with no other specified state.
If I say Given B is logged in, that is the same as “Given B is a ippa agent; And B is logged in (with appropriate line breaks, of course)
If I say Given B is ready, that is the same as “Given B is a ippa agent; And B is logged in; And B is ready”
In other words, the code that handles the “Given B is ready” would look at B’s current state, and configure B to be an ippa agent, who is logged in, and ready, if it’s not already in that state.
So the question is: Is it better to explicitly state the individual “Given/And” steps, or is it better to subsume them? In your experience, is it better to be wordy/explicit, or concise?
----
Part 2: You definitely need to find the balance between what you assume, and being too wordy. In this particular scenario, if there's no other kind of user besides an IPPA agent, then you can skip defining it as an IPPA agent altogether.
--
Thanks for your comments, Ramon.
For part 1, at the moment I’m just exploring. Baby steps first, then real functionality tests come later.
To answer a couple of the questions:
1) The thing I’m testing is the server, which is why the scenarios talk about agents and stuff – these are the things that connect to the server, so the cuke tests simulate a number of clients.
2) There are different kinds of agents (that is, there are different kinds of client programs connecting to the server, with different capabilities), so it is important to differentiate between them
3) I’ll work on groupings. It’s a little tricky because I’m using cuke4nuke, so the code itself runs out-of-process and can’t easily invoke steps back in cucumber.
From: cu...@googlegroups.com [mailto:cu...@googlegroups.com] On Behalf Of Ramon Tayag
Sent: Tuesday, April 13, 2010
12:23 PM
To: cu...@googlegroups.com
You may want to look into Background [http://wiki.github.com/aslakhellesoy/cucumber/background] and Scenario Outlines [http://wiki.github.com/aslakhellesoy/cucumber/scenario-outlines].
Background allows you to set up known state (i.e., Given agents A, B, C exist).
Scenario outlines allow you to write scenarios to pound on a given scenario for different data. For example:
Scenario Outline: logging in different agents
Given there is an agent <agent name>
And <agent name> goes to login page
And <agent name> logs in
Then <agent name> should see "<greeting text>"
Examples:
| agent name | greeting text |
| bob | Hello, Bob! |
| richard | Admin: Richard |
| hacker | Access denied |
Anyhow, that's one approach you can take to this.
[If there is a more appropriate place to send messages like this, let me know]
Hi Richard, one thing I’ve noticed with cuke4nuke. If you get the regular expression syntax wrong, then cuke4nuke exits with an exception with no notification of what was wrong. It would be nice if the exception was trapped and an appropriate message was logged instead to the cucumber output.
For example (and this has hit me several times, until finally I went “duh”) if you put a curly-brace instead of an open-parens, it crashes:
[When("^(.*) logs in$")] is correct; but [When("^{.*) logs in$")] is broken.
Thanks,
Richard
I'm surprised that this Regexp doesn't cause a runtime error. The
quality of the error message from a badly formed Regexp will depend on
the host language's Regexp engine.
What does .NET say for this?
new RegExp("^{.*) logs in$");
Aslak
Thanks,
Richard
Thanks for your comments, Ramon.For part 1, at the moment I’m just exploring. Baby steps first, then real functionality tests come later.To answer a couple of the questions:1) The thing I’m testing is the server, which is why the scenarios talk about agents and stuff – these are the things that connect to the server, so the cuke tests simulate a number of clients.2) There are different kinds of agents (that is, there are different kinds of client programs connecting to the server, with different capabilities), so it is important to differentiate between them3) I’ll work on groupings. It’s a little tricky because I’m using cuke4nuke, so the code itself runs out-of-process and can’t easily invoke steps back in cucumber.
--
You received this message because you are subscribed to the Google Groups "Cukes" group.
To post to this group, send email to cu...@googlegroups.com.
To unsubscribe from this group, send email to cukes+un...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/cukes?hl=en.