I'm taking my first steps with unit testing and have a problem with encapsulation. My class has some private member variables that shouldn't be visible to the client, but in order for me to put object in a state I want to test it under, I need to set those private variables.
Say I have a code like that:
Class Foo {
public:
int action() ;
private:
int state ;
} ;
int Foo::action()
{
if(this->state == 1)
return 1 ;
else
return 0 ;
}
So now I want to test Foo::action(), but I need to be able to set Foo::state to be able to check function under different scenarios. One solution is the evil "define private public" in tests code. But is there something more elegant? I would like to stress that Foo::state is a variable that shouldn't be accessed by client, so I don't want to declare any public setter.
Edit:
I now think that extending the class I want to test in test code and including setters in that derived class would work, providing I changed private variables to protected. But that's a 'one generation only' solution and still feels like a hack rather than a proper approach.
Edit 2:
After reading answers and comments I was given (thanks to Lieven and ap. in particular) I believe the actual class I'm trying to test now (not the simple example I provided) simply does too much and the answer to my problem is moving some of its logic into another class that will be used by the big guy.
There are only two posibilities (refactoring asside)
Use the public interface to set the state.
The state is redundant if you can't set it to through the public interface.
Option 2 is self explanatory and most likely not applicable to your case so you are left with setting the state through the public interface of your class.
As you have already mentioned, this is possible but it requires a lot of code to get to the right state. That in itself could be an indication that your class is currently doing to much and it's time to refactor parts of your class into smaller, testable classes.
From Do not test private methods
If you find the need to test a private method, then you’re doing
something else wrong. There is an “upstream” problem, so to speak. You
have arrived at this problem due to some other mistake previous in
this process. Try to isolate what that is, exactly, and remove that
rather than bending your tests to go down a painful road of
brittleness in testing.
and Unit testing private members
I'd recommend not unit testing private methods. Since they're
private, they may be changed in any conceivable (or inconceivable?)
manner between each release. If a given private method is so critical
to the operation of the class that you feel it deserves test cases,
then it's probably time to refactor that out into a protected or
public method
A common quote on this is
You should never touch your privates
If your test class is called MyTestClass, then add MyTestClass as friend in class Foo to be able to access its private member variables.
Class Foo {
public:
int action();
private:
int state;
friend class MyTestClass;
};
You should be having some publicly (or "protectedly") accessible mechanism to change the value of the private variable state. For simplicity, let's say it is a method Foo::setState(int inState). Use that in the unit test to change the state, and thus test the Foo::action() method. This ensures that any future implementation changes would not affect the unit test (unless the "API" Foo::setState() changes - in which case, of course, you have to change the unit test).
If you do not have such a mechanism to change state, it means the end user or calling code cannot change it either, and hence, you wouldn't need to test it (and maybe that makes state redundant, but I don't know about that).
If the private variable changes "indirectly" through other code, you will have to execute the same code in the unit test. You can always trace back any method visible externally to inputs fed to the code externally. Basically the point is that in the unit test, you would have to feed the same inputs to the code as in the "real" scenario, and then test if it responds as it should.
As discussed in the comments below, if the "path" from the input to the code being tested is too long, the code/test may have to be broken into smaller modules or intermediate points. To elaborate, consider the code flow as:
Input -> A -> B -> C -> Output
// A, B, C are intermediate execution points which are not "publicly accessible".
In the above case, all you can do is
Given Input, check if Output is correct.
Instead, it would be good to expose the intermediate A, B, C, at least to the unit tests, so that you can now break your test into:
Given Input, check if A is correct.
Given A, check if B is correct.
Given B, check if C is correct.
Given C, check if Output is correct.
As you can imagine, if the test fails, it becomes easier to figure out what failed, and hence to fix it.
Related
Let us assume that you've got a class in C++, for example with an internal state machine that is hard to test. Assume that you have a proper architecture with mocks for all classes used by the class under test. The class under test has some public interface and some non-public internal implementation.
You want to properly unit test this class. In order to make sure that all parts of it work correctly you would like to create some example conditions that you would not allow through the public interface. However, you want to test whether, under these circumstances, the system reacts correctly or not.
One possibility would be to make your member variables protected, so that an inherited class, specifically created for unit testing, is able to extend the public interface to control those variables during testing. You could then, for example, set the system to a certain state, set some internal variables and make sure that e.g. the state transition is according to your requirements.
From a design point of view: Is it justifiable to make non-public members protected in order to be able to get them more testable? What are your opinions? Are there better alternative design decisions?
I had a similar issue. To be honest , I don't see a point why you should not also test the private part of a class.
My solution to this was using the pre-compiler only for the private statement.
#ifndef UNITTEST
private:
#endif // UNITTEST
Of course we could argue now, that I am manipulating the original class itself and I am not any longer testing properly in real conditions , but if you are testing one class and not several within this one unit test I see no issue.
This question about the protected is a bit like the question about making methods virtual for the sake of mocking. You have to decide case by case.
I have this problem. I have a method in a class which gives me some return value. This method also makes changes to the state of the instance of that class. I need to unit test them both, so I made the test cases for the return value and copied them and just changed the assert from testing the return value to testing the change in representation (the only way for me to test this class is to test its representation). However, this does not seem like a very good way to deal with this. If I ever have changes in the functionality of the class, I will have to change the Act in the AAA in both test cases. How do I go about testing this? Is there some pattern to do that? Having both asserts in one test would mean I would be testing two things in one test case. In some languages (like JavaScript), I know I can make an array of tuples with the functionality, the assert for the return value and the assert for the representation, but I'm not sure a) how much better that is over some copy-pasting and b) what to do in other languages (e.g. in C# I imagine I'd have to make some classes with the asserts and include them in test cases).
Edit: For example:
class A {
state;
foo(animal, foodAmount) {
let returnResult = {};
//does things with animal and foodAmount
//which things change BOTH returnResult and the state variable
return returnResult;
}
bar() {
let stateToReturn = "";
//state is used to change the stateToReturn variable
return stateToReturn;
}
}
Here I will test function foo with a) an animal that does not exist currently, b) an animal that exists where I will add a non-zero amount of food to make sure the amount of food changes, c) two different animals to make sure they do not interfere with each other's food amounts, etc. I will do all these tests and make sure the returnResult variable is correct. The problem is that I need to make sure it does not only affect the returnResult variable, but also the state. The bar function is the only way for me to see the inner state. How would I go about testing the foo function? Would I write all tests twice (once to check foo returns the correct result and once to check foo changes the state correctly)?
Even with your example it's still a bit vague. The general and short answer to your question is: You should test for behavior, not methods. If that requires you to make assertions on the result of multiple methods in one test that's perfectly fine.
You shouldn't, however, expose the internal state of your class just to make it testable. It's better to test against the public api of your class. After all, that's how the production code interacts with it.
If a method changes the internal state but there is nothing in the public api that makes the change visible, how do you test it? You probably have a hidden concept in your class that should be extracted into its own class with its own public api. You can test the new class independently and the interaction between the two classes. This leads to smaller and more focused tests.
I'm not sure if this answers your question sufficiently but maybe there's some food for thought.
I want to use Google test to test my class.
Lets assume I have a state machine implementation and the current state is private
so I have a method SetNextState that looks like that:
void setNextState
{
switch(m_currentState) //m_currentState is a private member
{
case INIT_STATE:
{
if some conditions occurred m_currentState=GO_STATE
}
......
}
}
so I have several cases and each define the behavior to move from certain state to another.
My question:
How do I perform tests on that method assuming the state is relevant only to this class so there is no output
How do I set its value to be, for example "GO_STATE" to test the GO_STATE case
and how do i check the m_currentState at the end of the test
Im trying to avoid putting friends etc. in my UUT code since I want it to be as original as possible
You don't. You do the same thing that your actual program will do, which is provide an input, then examine the result; you say there's no output, but there must be some effect, otherwise the class is pointless!
Failing that, you could make the test a "friend" of the class so that it can inspect its internals, or add an immutable getter for the current state (and who really cares if your class's users get to see that?) but neither option is really in the spirit of the thing.
In my experience, you'll occasionally realise that you're not really unit testing any more but instead functional testing, and Google Test may not be the right tool for that job. If your class is as big as it sounds, that could be the case here. Conversely, you could help yourself by splitting the class into smaller chunks, then unit testing those. Depends what you're going for, really.
Lightness Races in Orbit is correct. However, if sometimes you feel like it's useful to test the private member functions of your class, it often means that your class could be split in multiple smaller pieces.
If you don't think those smaller components are useful to the clients of your library, you can simply hide them in a detail:: namespace and then create unit tests as usual. This will allow you to test the internal behavior of your classes without polluting your public API.
After much considerations I decided to wrap my UUT with a helper which provides set and get to the relevant private members.and use it in the test procedure before calling the tested API
Original code
===============
class UUT //That's the actual class I want to test
{
protected:
int m_protectedMember;
public:
void methodToTest()
{
//Do something with m_protectedMember use its value as input
//and set it as output
}
};
In the tester
==============
class UUTHelper: public UUT
{
public:
int getProtectedMember() { return m_protectedMember; }
void setProtectedMember(int value) { m_protectedMember = value; }
};
The pros:
My test code is very simple and I easily create complicated scenarios .
I test the real code without any "friends" or any other manipulations.
The cons:
As written in the discussion, not the best "good practice", touching private members
Thank you all :)
I have a C++ class that generates unique IDs in the following fashion.
class Foo
{
static int seed;
public:
const int Uid;
Foo() : Uid(seed++) {}
}
int Foo::seed = 0;
Now I'm using Google Test to test this Id generator using:
Foo foo;
EXPECT_EQ(0, foo.Uid);
Foo foo2;
EXPECT_EQ(1, foo2.Uid);
This test passes when I debug it but fails when I actually run it, giving me IDs of 2 and 3 instead. Can someone help me figure out why? Is Google test running two of these tests back-to-back or something?
One of characteristics of good tests is repeatability with not depending on tests order execution.
You have a singleton, and you use it in a bad way. If we assume there are no memory problems, then what most likely happens, is that the object of type Foo is somewhere created, and that your tests are getting executed in different order for debug and normal runs. That would explain different results.
How to fix? The simplest hack would be to add a method to reset the counter, and call it in setUp(). To fix it properly, you need to think how to remove that singleton.
BЈовић's answer will get you there. It's likely that somewhere else in your test code another instance of Foo is created that increases the value of the static member.
This may be a less hacky solution and possibly useful if adding a public reset method is not applicable (i.e. you don't want to add test-specific code to your API):
Mock classes. Add a class that dervies from Foo. Change the access level of your static variable from private to protected and add the new reset method to the protected class. You can then refactor your test code to run off of the derived class.
Make FooTester a friend of Foo. Via class friend ship you're allowing your test code more manipulation over the class under test.
I recommend going with the mock route. Keeps the original class clean of any test specific hacks and allows you to be more aware of any exposures in its interface.
Consider the following class:
public class MyIntSet
{
private List<int> _list = new List<int>();
public void Add(int num)
{
if (!_list.Contains(num))
_list.Add(num);
}
public bool Contains(int num)
{
return _list.Contains(num);
}
}
Following the "only test one thing" principle, suppose I want to test the "Add" function.
Consider the following possibility for such a test:
[TestClass]
public class MyIntSetTests
{
[TestMethod]
public void Add_AddOneNumber_SetContainsAddedNumber()
{
MyIntSet set = new MyIntSet();
int num = 0;
set.Add(num);
Assert.IsTrue(set.Contains(num));
}
}
My problem with this solution is that it actually tests 2 methods: Add() and Contains().
Theoretically, there could be a bug in both, that only manifests in scenarios where they are not called one after the other. Of course, Contains() now servers as a thin wrapper for List's Contains() which shouldn't be tested in itself, but what if it changes to something more complex in the future? Perhaps a simple "thin wrap" method should always be kept for testing purposes ?
An alternative approach might suggest mocking out or exposing (possibly using InternalsVisibleTo or PrivateObject) the private _list member and have the test inspect it directly, but that could potentially create test maintainability problems if someday the internal list is replaced by some other collection (maybe C5).
Is there a better way to do this?
Are any of my arguments against the above implementations flawed?
Thanks in advance,
JC
Your test seems perfectly OK to me. You may have misunderstood a principle of unit testing.
A single test should (ideally) only test one thing, that is true, but that does not mean that it should test only one method; rather it should only test one behaviour (an invariant, adherence to a certain business rule, etc.) .
Your test tests the behaviour "if you add to a new set, it is no longer empty", which is a single behaviour :-).
To address your other points:
Theoretically, there could be a bug in both, that only manifests in scenarios where they are not called one after the other.
True, but that just means you need more tests :-). For example, add two numbers, then call Contains, or call Contains without Add.
An alternative approach might suggest mocking out or exposing (possibly using InternalsVisibleTo) the private _list member and have the test inspect it directly, but that could potentially create test maintainability problems[...]
Very true, so don't do this. A unit test should always be against the public interface of the unit under test. That's why it's called a unit test, and not a "messing around inside a unit"-test ;-).
There are two possibilities.
You've exposed a flaw in your design. You should carefully consider if the actions that your Add method is executing is clear to the consumer. If you don't want people adding duplicates to the list, why even have a Contains() method? The user is going to be confused when it's not added to the list and no error is thrown. Even worse, they might duplicate the functionality by writing the exact same code before they call .Add() on their list collection. Perhaps it should be removed, and replaced with an indexer? It's not clear from your list class that it's not meant to hold duplicates.
The design is fine, and your public methods should rely on each other. This is normal, and there is no reason you can't test both methods. The more test cases you have, theoretically the better.
As an example, say you have a functions that just calls down into other layers, which may already be unit tested. That doesn't mean you don't write unit tests for the function even if it's simply a wrapper.
In practice, your current test is fine. For something this simple it's very unlikely that bugs in add() and contains() would mutually conspire to hide each other. In cases where you are really concerned about testing add() and add() alone, one solution is to make your _list variable available to your unit test code.
[TestClass]
public void Add_AddOneNumber_SetContainsAddedNumber() {
MyIntSet set = new MyIntSet();
set.add(0);
Assert.IsTrue(set._list.Contains(0));
}
Doing this has two drawbacks. One: it requires access to the private _list variable, which is a little complex in C# (I recommend the reflection technique). Two: it makes your test code dependent on the actual implementation of your Set implementation, which means you'll have to modify the test if you ever change the implementation. I'd never do this for something as simple as a collections class, but in some cases it may be useful.