How to extract test name in Google Test's case method? - googletest

I've a bunch of test cases in which each case would output a file. I'd like each files would be named after the corresponding case name so the result files won't get in the way with each other. Is there any way to do that by programming?
What I have now (hate to repeat the case name since it could be changed:
TEST_F(Foo, Bar)
{
...
std::ofstream("Bar.bat");
...
}
What I want:
TEST_F(Foo, Bar)
{
...
std::ofstream(magic_method_to_get_case_name() + ".dat");
...
}

The current test's name can be accessed via the UnitTest singleton class.
::testing::UnitTest::GetInstance()->current_test_info()->name();
Because UnitTest is a singleton, this can be called from static/global test utility methods as well.

Just find out how to do that. I'll share it here in case anyone would like to know it.
Looks like GTEST_TEST_ macro would keep the name information in a private static variable:
#define GTEST_TEST_(test_case_name, test_name, parent_class, parent_id)\
class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) : public parent_class {\
public:\
GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {}\
private:\
virtual void TestBody();\
static ::testing::TestInfo* const test_info_;\
GTEST_DISALLOW_COPY_AND_ASSIGN_(\
GTEST_TEST_CLASS_NAME_(test_case_name, test_name));\
};\
So, the code in any case could get the case name through it:
test_info_->name()
Case name is not the only information that could be fetched -- please check the TestInfo class in gtest.h.

Related

GoogleTest: is there a generic way to add a function call prior to each test case?

my scenario: I have an existing unit test framework with ~3000 individual test cases. They are made from TEST, TEST_F and TEST_P macros.
Internally the tested modules make use of a logger library and now my goal is to create individual log files for each test case. To do so I would like to call a function as a SetUp for each test case.
Is there a way to register such function at the framework and get it called automatically?
The obvious solution for me would look like: do the work in a test fixture constructor or SetUp() but then I'd have to touch every single test case.
I do like the idea of registering a global setup at the framework with AddGlobalTestEnvironment() but as I understand this is handled only once per executable.
By the way: I have acceptance tests implemented in robot test and guess what? I want to repeat the task there...
Thanks for any inspiration!
Christoph
You mentioned:
The obvious solution for me would look like: do the work in a test fixture constructor or SetUp() but then I'd have to touch every single test case.
If the reason that you think you would need to touch every single test case is to set the filename differently, you can use the combination of SetUp() function and the current_test_info provided by GTest to get the test name for each test, and then use that to create a separate file for each test.
Here is an example:
// Class for test fixture
class MyTestFixture : public ::testing::Test {
protected:
void SetUp() override {
test_name_ = std::string(
::testing::UnitTest::GetInstance()->current_test_info()->name());
std::cout << "test_name_: " << test_name_ << std::endl;
// CreateYourLogFileUsingTestName(test_name_);
}
std::string test_name_;
};
TEST_F(MyTestFixture, Test1) {
EXPECT_EQ(this->test_name_, std::string("Test1"));
}
TEST_F(MyTestFixture, Test2) {
EXPECT_EQ(this->test_name_, std::string("Test2"));
}
Live example here: https://godbolt.org/z/YjzEG3G77
The solution I found in the gtest docs:
class TraceHandler : public testing::EmptyTestEventListener
{
// Called before a test starts.
void OnTestStart( const testing::TestInfo& test_info ) override
{
// set the logfilename here
}
// Called after a test ends.
void OnTestEnd( const testing::TestInfo& test_info ) override
{
// close the log here
}
};
int main( int argc, char** argv )
{
testing::InitGoogleTest( &argc, argv );
testing::TestEventListeners& listeners =
testing::UnitTest::GetInstance()->listeners();
// Adds a listener to the end. googletest takes the ownership.
listeners.Append(new TraceHandler);
return RUN_ALL_TESTS();
}
This way it automatically applies to all tests linked to this main-function.
Maybe I have to mention: my logger is a collection of static functions that send udp-packets to a receiver that cares for actual logging. I can control the filename by one of that functions. That's the reason why I don't need to insert code in every single TEST, TEST_F or TEST_P.

wxDataViewListCtrl and wxVariant

I have a simple setup, a wxDataViewListCtrl, the first column uses wxDataViewCustomRenderer and the second column is just text.
class MyCustomRenderer : public wxDataViewCustomRenderer
I add a line to the wxDataViewListCtrl like this:
wxVector<wxVariant> item;
item.push_back(wxVariant(/*a raw pointer of MyClass goes here*/));
item.push_back(wxVariant("some string goes here"));
m_data_view_list_ctrl->AppendItem(item);
item.clear();
And this is MyClass:
class MyClass final : public wxObject
And this is how my SetValue method looks like:
bool MyCustomRenderer::SetValue(const wxVariant& value)
{
MyClass* temp = static_cast<MyClass*>(value.GetWxObjectPtr());
/*Do stuff with temp here...*/
return true;
}
It worked, now it does not. It fails with the following error:
https://www.dropbox.com/s/acxbzthp3ltadny/wxwidgets.png?dl=0
The only thing I changed is that I updated my static libs of wxWidgets from 3.0.4 to 3.1.2.
Why has it stopped working? What am I missing here?
Please help me :-)
Update
Thank you all for answering. The problem was solved here. In short I needed to change this line like this:
MyCustomRenderer::MyCustomRenderer() : wxDataViewCustomRenderer("void*", wxDATAVIEW_CELL_INERT, wxALIGN_CENTER)
And this one like this:
item.push_back(wxVariant(static_cast<void*>(/*Raw pointer to an instance of MyClass*/)));
I'm not sure which change exactly is responsible for this, but the value, returned by your model for the cell being drawn, is null, so your renderer can't just use it blindly and should check if ( !value.IsNull() ) before doing it (and maybe just return in this case or do whatever is appropriate to show the absence of a value in your case).

Actionscript, can a class be accessed using a variable name?

I wish to access many classes and variables, I would like to do this by dynamically setting the class name and variable name. Currently I am using
MyClass["myVariable1"]
to dynamically access the variable name
MyClass.myVariable1
I want to also dynanmically acces the class name, something like
["MyClass"]["myVariable1"]
But this does not work.
The purpose is that I have shared object with many user settings, I want to iterate through the shared object and set all the user settings across all the classes. I think if I cant dynamically access the class I must have a statement for each and every class name/variable.
I advise against such a practice. Although technically possible, it is like welcoming a disaster into the app architecture:
You rely on something you have no apparent control of: on the way Flash names the classes.
You walk out of future possibility to protect your code with identifier renaming obfuscation because it will render your code invalid.
Compile time error checks is better than runtime, and you are leaving it to runtime. If it happens to fail in non-debug environment, you will never know.
The next developer to work with your code (might be you in a couple of years) will have hard time finding where the initial data coming from.
So, having all of above, I encourage you to switch to another model:
package
{
import flash.net.SharedObject;
public class SharedData
{
static private var SO:SharedObject;
static public function init():void
{
SO = SharedObject.getLocal("my_precious_shared_data", "/");
}
static public function read(key:String):*
{
// if (!SO) init();
return SO.data[key];
}
static public function write(key:String, value:*):void
{
// if (!SO) init();
SO.data[key] = value;
SO.flush();
}
// Returns stored data if any, or default value otherwise.
// A good practice of default application values that might
// change upon user activity, e.g. sound volume or level progress.
static public function readSafe(key:String, defaultValue:*):*
{
// if (!SO) init();
return SO.data.hasOwnProperty(key)? read(key): defaultValue;
}
}
}
In the main class you call
SharedData.init();
// So now your shared data are available.
// If you are not sure you can call it before other classes will read
// the shared data, just uncomment // if (!SO) init(); lines in SharedData methods.
Then each class that feeds on these data should have an initialization block:
// It's a good idea to keep keys as constants
// so you won't occasionally mistype them.
// Compile time > runtime again.
static private const SOMAXMANA:String = "maxmana";
static private const SOMAXHP:String = "maxhp";
private var firstTime:Boolean = true;
private var maxmana:int;
private var maxhp:int;
// ...
if (firstTime)
{
// Make sure it does not read them second time.
firstTime = false;
maxhp = SharedData.readSafe(SOMAXHP, 100);
maxmana = SharedData.readSafe(SOMAXMANA, 50);
}
Well, again. The code above:
does not employ weird practices and easy to understand
in each class anyone can clearly see where the data come from
will be checked for errors at compile time
can be obfuscated and protected
You can try getting the class into a variable and going from there:
var myClass:Class = getDefinitionByName("MyClass") as Class;
myClass["myVariable1"] = x;

Can I give better names to value-parameterized tests in gtest?

I use value-parameterized tests in gtest. For example, if I write
INSTANTIATE_TEST_CASE_P(InstantiationName,
FooTest,
::testing::Values("meeny", "miny", "moe"));
then in the output I see test names such as
InstantiationName/FooTest.DoesBlah/0 for "meeny"
InstantiationName/FooTest.DoesBlah/1 for "miny"
InstantiationName/FooTest.DoesBlah/2 for "moe"
Is there any way to make these names more meaningful? I'd like to see
InstantiationName/FooTest.DoesBlah/meeny
InstantiationName/FooTest.DoesBlah/miny
InstantiationName/FooTest.DoesBlah/moe
INSTANTIATE_TEST_CASE_P accepts an optional 4th argument which can be used for this purpose. See https://github.com/google/googletest/blob/fbef0711cfce7b8f149aac773d30ae48ce3e166c/googletest/include/gtest/gtest-param-test.h#L444.
This is now available in INSTANTIATE_TEST_SUITE_P.
The optional last argument to INSTANTIATE_TEST_SUITE_P() allows the
user to specify a function or functor that generates custom test name
suffixes based on the test parameters.
Of interest is also this section in the source:
// A user can teach this function how to print a class type T by
// defining either operator<<() or PrintTo() in the namespace that
// defines T. More specifically, the FIRST defined function in the
// following list will be used (assuming T is defined in namespace
// foo):
//
// 1. foo::PrintTo(const T&, ostream*)
// 2. operator<<(ostream&, const T&) defined in either foo or the
// global namespace.
Two ways: (http://osdir.com/ml/googletestframework/2011-09/msg00005.html)
1) Patch the existing PrettyUnitTestPrinter to print test names; something like:
--- a/gtest-1.7.0/src/gtest.cc
+++ b/gtest-1.7.0/src/gtest.cc
## -2774,6 +2774,7 ## void PrettyUnitTestResultPrinter::OnTestCaseStart(const TestCase& test_case) {
void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo& test_info) {
ColoredPrintf(COLOR_GREEN, "[ RUN ] ");
PrintTestName(test_info.test_case_name(), test_info.name());
+ PrintFullTestCommentIfPresent(test_info);
printf("\n");
fflush(stdout);
}
2) Write a new TestListener to print test results however you like. (https://code.google.com/p/googletest/source/browse/trunk/samples/sample9_unittest.cc) GTest allows registering a new test listener (and un-registering the builtin default), allowing pretty flexible customization of test output. See the link for example code.

store in a variable only the first or only the second class of an element

I'm using this bit of jQ to add a class to two different elements based on the class of another (parent/grandparent, etc) element:
$(document).ready(function(){
var containerClass = $('#main-content').attr('class');
$('#nav-primary li#'+containerClass).addClass('active');
$('#aux-left div[id$='+containerClass+']').addClass('active');
});
Brilliant, but I have two problems with it:
First, when there's no class at all in <div id="main-content">, the 'active' class is added to all the #nav-primary LIs, and also to all the #aux-left DIVs; how can I modify this so that in the absence of any class on #main-content, do nothing?
Second, how can I target only the first or second of multiple classes to store in the 'containerClass' variable, e.g., <div id="main-content" class="apples bananas">?
Very much appreciated! svs
For 1: do an if-clause after your first line, e.g. like this:
if(containerClass.length > 1) {
//your addClass code
}
//EDIT: The above would be placed after you define containerClass in your script. It just checks if the container has a class or not, by measuring the content of the variable (.length). If containerClass = "", this if-condition will be false, and the contained code will not execute. Hence it should prevent your first problem from happening: that the "active" class is added to all its children, regardless of #main-content having a class or not
For 2:
classes = containerClass.split(' '); //split by space
if(classes[1]) { //if there is a 2nd class
//do something if there are multiple classes
//access the 1st class with classes[0], etc.
} else {
//do something if #main-content only has 1 class
}
//EDIT: in the above, the first line splits whatever the variable containerClass contains by an empty space. You can compare that with php's explode function: Say your container has 2 classes (class="aplles bananas"), what you'll end up with after splitting that by empty space is an array that contains both of these classes like this:
classes[0] = 'apples';
classes[1] = 'bananas';
So now you have your 1st and 2nd classes, if they exist.
The next line in my code would then do something if #main-content has a 2nd class (here: "bananas"), but you could also check against the first class with
if(classes[0]) { ...
The "else" part in my code would trigger if #main-content doesn't have a 2nd class. You could expand the above if-else-condition by first checking if a 1st class exists, then checking if a 2nd class exists, and then doing something else (or nothing) if #main-content doesn't have any classes at all. I hope this makes it clearer.
Hope this helps. On an unrelated note, you might want to add "jquery" to the tags of this post so that more people can find it :)
Still not quite there ... I'll try again, hoping this is of use to others:
Here's where I'm at (having temporarily set aside the need to check that there's at least one class):
$(document).ready(function(){
contentClasses = $('#main-content').attr('class');
contentClass = contentClasses.split(' '); // split by space
$('#nav-primary li#'+contentClass).addClass('active');
$('#aux-left div[id$='+contentClass+']').addClass('active');
}); // close doc.ready
... but this is not working as intended if there's more than one class on <div id="main-content">. Oddly, the 'active' class IS being added to the appropriately to #nav-primary LI but not to #aux-left div. The console reports the following: "Warning: Expected ']' to terminate attribute selector but found ','."
Any clarification would be greatly appreciated. svs