IAM

OPENSOURCEFAN STUDYING
STUDYINGCOMPUTERSCIENCEANDMATH COMPUTERSCIENCE

Check out the latest superpixel benchmark — Superpixel Benchmark (2016) — and let me know your opinion! @david_stutz
15thOCTOBER2016

SNIPPET

C++

Implementation of the example in Martin Fowler’s “Mocks Aren’t Stubs” using GoogleMock.

mail_service.hpp
/** \brief Mail service. This represents one of the collaborators of the SUT. 
 * \author David Stutz
 */
class MailService
{
public:
    /** \brief Send a mial.
     * \param[in] message message to send
     */
    virtual void send(std::string message) = 0;
    
};
a
order.hpp
#include <string>
#include <memory>
#include "warehouse.hpp"
#include "mail_service.hpp"

/** \brief An order of a product with quantity. */
class Order
{
public:
    /** \brief Constructor.
     * \param[in] quantity quantity requested
     * \param[in] product product name requested
     */
    Order(int quantity, std::string product)
    {
        this->quantity = quantity;
        this->product = product;
    }
    
    /** \brief Set the mail service to use. 
     * \param[in] mailService the mail service to attach
     */
    void setMailService(std::shared_ptr<MailService> mailService)
    {
        this->mailService = mailService;
    }
    
    /** \brief Fill the order given the warehouse. 
     * \param[in] warehouse the warehouse to use
     * \return whether the operation was successful
     */
    bool fill(Warehouse &warehouse)
    {
        if (warehouse.hasInventory(quantity, product))
        {
            // ...
            warehouse.remove(quantity, product);
            this->mailService->send("Order filled.");
            
            return true;
        }
        else
        {
            // ...
            this->mailService->send("Order not filled.");
            
            return false;
        }
    }
    
private:
    
    /** \brief Product name. */
    std::string product;
    
    /** \brief Quantity requested. */
    int quantity;
    
    /** \brief Mail service to use. */
    std::shared_ptr<MailService> mailService;
};
warehouse.hpp
#include <string>

/** \brief Warehouse interface. This interface is one of the collaborators of our SUT.
 * \author David Stutz
 */
class Warehouse
{
public:
    /** \brief Check whether the product in the given quantity is on stock.
     * \param[in] quantity quantity requested
     * \param[in] product product name
     * \return whether the warehouse has the product on stock for the given quantity
     */
    virtual bool hasInventory(int quantity, std::string product) const = 0;
    
    /** \brief Remove the given quantity of the product from the warehouse.
     * \param[in] quantity quantity to remove
     * \param[in] product product name to remove
     */
    virtual void remove(int quantity, std::string product) = 0;
    
};
main.cpp
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "lib/mail_service.hpp"
#include "lib/warehouse.hpp"
#include "lib/order.hpp"

using ::testing::Return;
using ::testing::_; // Matcher for parameters

/** \brief Mock for the warehouse interface.
 * \author David Stutz
 */
class MockWarehouse : public Warehouse
{
public:
    
    // see https://github.com/google/googletest/blob/master/googlemock/docs/ForDummies.md
    MOCK_CONST_METHOD2(hasInventory, bool(int, std::string));
    MOCK_METHOD2(remove, void(int, std::string));
};

/** \brief Mock for the mail service interface. 
 * \author David Stutz
 */
class MockMailService : public MailService
{
public:
    MockMailService()
    {
        
    }
    
    MOCK_METHOD1(send, void(std::string));
};

TEST(OrderTest, Fill)
{
    MockWarehouse warehouse;
    std::shared_ptr<MockMailService> mailService = std::make_shared<MockMailService>();
    
    Order order(50, "Talisker");
    order.setMailService(mailService);
    
    EXPECT_CALL(warehouse, hasInventory(50, "Talisker"))
        .Times(1)
        .WillOnce(Return(true));
    EXPECT_CALL(warehouse, remove(50, "Talisker"))
        .Times(1);
    
    EXPECT_CALL(*mailService, send(_)) // Not making assumptions on the message send ...
        .Times(1);
    
    ASSERT_TRUE(order.fill(warehouse));
}

/** \brief Main test entrance point. 
 * \param[in] argc
 * \param[in] argv
 */
int main(int argc, char** argv) {
    ::testing::InitGoogleMock(&argc, argv);
    return RUN_ALL_TESTS();
}

What is your opinion on the code snippet? Is it working? Let me know your thoughts in the comments below or using the following platforms: