Tuesday, November 12, 2013

VS2012 and Gmock - Writing your mock classes

This video is the fifth in a series of videos that show how to use VS2012 and google test and mock. Before watching this video you should make sure that you have already setup your Visual Studio solution to have a googlemock, googletest and a unit level test project. If you do not know how to do this check out the previous videos/blogs in the series.
In this video I will show you how to write a mock class and then how to use the mock class in writing you unit level tests.



First you should understand what a mock class is. A Mock is fake object in the system that replaces a dependency and verifies whether the object under test interacted as expected with the dependency.

To understand this better check out the architecture of the BitcoinWallet Class.

BitcoinWallet has dependency on three other classes. BitcoinBank, BitcoinTransaction, and BitcoinCommerce. But we only want to focus our testing on BitcoinWallet. We don't want to call the implementation of BitcoinBank. BitcoinBank could have an implementation that actually calls a bank. That would be a bad thing if every time we ran our unit level tests it transferred money from one account to another. :) So we need to create a Mock to replace the real classes.


Put the mocks in place allows Bitcoin to be tested by itself and without exercising the other classes in the architecture. Here are some examples of what the mock classes look like.

#include <gmock/gmock.h>
#include "BitcoinTransaction.h"

class BitcoinTransaction_Mock : public BitcoinTransaction {
public:
MOCK_METHOD3(set,void(const string&, const string&, long));
MOCK_METHOD0(amount, int(void));
};

There are a couple things you need to watch out for when using Google Mock.

  • Only virtual methods can be Mock(ed)
  • If you don't have virtual methods check out the documentation on gmock on how to work around the problem. https://code.google.com/p/googlemock/
  • You must always put a mock method definition (MOCK_METHOD*) in a public: section of the mock class
  • Your Mock Method must match the cardinality of the real method.
  • Mocked classes do not do anything. They just pass back data.
Check my next video where I discuss how to use ON_CALL and EXPECT_CALL macros. But here is a small example of how to use the Mock classes and the ON_CALL macro.

#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include "BitcoinWallet.h"
#include "BitcoinBank_Mock.h"
#include "BitcoinCommerce_Mock.h"
#include "BitcoinCurrency_Mock.h"

using ::testing::Return;
using ::testing::_;

BitcoinBank* ExternalService::theBank = new BitcoinBank_Mock();
BitcoinCommerce* ExternalService::theCommerce = new BitcoinCommerce_Mock();
BitcoinCurrency* ExternalService::theCurrency = new BitcoinCurrency_Mock();

TEST(BitcoinWalletTest,updateLocalBalanceTestNoAccount) {
   BitcoinBank_Mock* bbm = new BitcoinBank_Mock();
   BitcoinWallet bw;
   ExternalService::theBank = bbm;
   ON_CALL(*bbm, changeBalance(_,_))
  .WillByDefault(Return(-1));

   ASSERT_EQ(bw.updateLocalBalance(),ActionStatus::AccountNotExist);
}

Monday, November 4, 2013

VS2012 and GMock - Getting Started Video #4


Using GoogleMock and VS2012 can be tricky. This video shows how to get things started so you aren't wasting time trying to figure out include paths, Pre-Processor directives and project configuration.
This video does not show you details of gmock just how to get it setup and begin using in your project. The next video will go into more details on how to use gmock effectively.
  1. Compile googlemock into a library.
    • Create a new project of static library: Add->New Project->Win32 Project->Static Library (no precompiled header)
    • Add include path <gmock_dir>, <gmock_dir>/include, <gtest_dir>, and <gtest_dir>/include
    • Add source file <gmock_dir>/src/gtest_all.cc and gtest_main.cc
    • Change the pre-processor rules to include the definition._VARIADIC_MAX =10
  2. Add references to Your Unit Test project.
    • Add the gmock project as an external reference.
    • Add the gmock include directories to Include Path <gmock_dir> and <gmock_dir>/include


When you have completed these steps you can now try and Mock one of the classes in the solution. The following is an example of a mock for the BitcoinTransaction class in our bitcoin solution.

BitcoinTransactionMock.h
#include <gmock/gmock.h>
#include "BitcoinTransaction.h"

class BitcoinTransactionMock : public BitcoinTransaction {
public:
   MOCK_METHOD3(set,void(const string&, const string&, long));
   MOCK_METHOD0(amount, int(void));
};


Now that I have a Mock(ed) class I can use the mocked class in my tests.

#include <gtest/gtest.h>
#include "BitcoinTransactionMock.h"
#include <gmock/gmock.h>

using ::testing::Return;
TEST(BitcoinTransactionMock,setGoodValues) {
   BitcoinTransactionMock* bt = new BitcoinTransactionMock();
   ASSERT_NE(bt, nullptr);
   ON_CALL(*bt, amount())
      .WillByDefault(Return(100));
   bt->set("MyAccount","YourAccount", 1000);
   ASSERT_EQ(bt->amount(), 100);
}


In this example The Macro ON_CALL is used to set the return value of the call to amount.
The next video and blog will go into more depth on how to use gmock and the benefits of isolation in unit level testing.

DWP.