WHAT
WHY
HOW
float sqrRoot(float a);
int main()
{
float input = 4;
float result = sqrRoot( input );
printf("square root of %f is %f\n", input, result);
return 0;
}
// square root of 4 is 2
We usually start with visual inspection...
A methodology to test that a UNIT of your code is doing what you want it to do.
A "unit testing framework" is a library that help us automating this process and reducing boilerplate in the code.
float sqrRoot(float a);
int main()
{
float input = 4.0;
float expected = 2.0;
float result = sqrRoot( input );
//warning, this might fail due to floating point comparison
if( result != expected )
{
printf("ERROR: square root of %f is %f instead of %f\n",
input, result, expected );
return ERROR_CODE;
}
bool exception_thrown = false;
try {
sqrRoot( -1 );
}
catch(...) {
exception_thrown = true;
}
if( !exception_thrown ){
printf("ERROR: exception hasn't been thrown by sqrRoot(-1) \n");
return ERROR_CODE;
}
return SUCCESS;
}
When we want to test more...
The "visual inspection" of larger applications
is even more time consuming.
Code
Compile
Observe result
This is even more true when you consider:
Spend time preventing bug or fixing bugs?
But of course there are also "bad" tests that are too superficial.
"it was working yesterday..."
If your code is not tested and not documented,
I might not trust it.
You and me know it is not
Sometimes 70% is better than 99.9%
#include "gtest/gtest.h"
TEST(SquareRootTest, PositiveNos)
{
EXPECT_FLOAT_EQ (2.0, sqrRoot (4.0) );
EXPECT_FLOAT_EQ (18.0, sqrRoot (324.0) );
EXPECT_FLOAT_EQ (25.4, sqrRoot (645.16) );
EXPECT_FLOAT_EQ (50.3321, sqrRoot (2533.310224) );
}
TEST (SquareRootTest, ZeroAndNegativeNos)
{
EXPECT_EQ (0.0, sqrRoot (0.0) );
EXPECT_ANY_THROW ( sqrRoot (-1.0) );
EXPECT_ANY_THROW ( sqrRoot (-22.0) );
}
int main(int argc, char **argv)
{
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
int main()
{
float input = 4.0;
float expected = 2.0;
float result = sqrRoot( input );
if( fabs(result - expected) < std::numeric_limit<float>::min() )
{
printf("ERROR: square root of %f is %f instead of %f\n",
input, result, expected );
return ERROR_CODE;
}
bool exception_thrown = false;
try {
sqrRoot( -1 );
}
catch(...) {
exception_thrown = true;
}
if( !exception_thrown ){
printf("ERROR: exception hasn't been thrown by sqrRoot(-1) \n");
return ERROR_CODE;
}
return SUCCESS;
}
TEST(SquareRootTest, MinimalTest)
{
EXPECT_FLOAT_EQ (2.0, sqrRoot (4.0));
EXPECT_ANY_THROW ( sqrRoot (-1.0))
}
// To use a test fixture, derive a class from testing::Test.
class DequeTest : public testing::Test {
protected: // You should make the members protected
// virtual void SetUp() will be called before each test is run.
virtual void SetUp()
{
q1_.Enqueue(1);
q1_.Enqueue(3);
q1_.Enqueue(5);
}
// virtual void TearDown() will be called after each test is run.
virtual void TearDown() {}
void copy(List* dq1, List* dq2){
l2->clear();
for(int i=0; l1->size(); i++){
l2->push_back( l1->at(i) );
}
}
// Declares the variables your tests want to use.
Deque<int> q0_;
Deque<int> q1_;
};
// When you have a test fixture, you define a test using TEST_F
TEST_F(DequeTest, DefaultConstructor) {
EXPECT_EQ(0, q0_.Size());
EXPECT_EQ(3, q1_.Size());
}
TEST_F(DequeTest, TestCopy) {
copy( &q1_, &q0_);
ASSERT_EQ( q0_.size() == q1_.size() );
for (int i=0; i< q0_.size(); i++){
EXPECT_EQ( q0_.at(i), q1_.at(i) );
}
}
Fixtures
No matter how many tests you write, you can not "prove" that your code is bug free.
Some bugs appear only in "production".
Summarizing...
All your tests are terrible
Pragmatic unit testing in C++