Wednesday, February 27, 2013

Code Kata: Recently opened files

Kata #2: Recently opened files
 
Implement a container that has the well known functionality of "Recently opened files" that you know from various applications you use:
  • the container must be able to list file paths that it stores
  • if file A is opened and right after that we ask the container to list the file paths it stores, the path to file A will be listed as the first one
  • the number of stored file paths is limited; when the limit is exceeded the container forgets least recently used file path
  • in the list of recently open files, each file path can appear once and only once

Tuesday, February 26, 2013

Code Kata: Vending Machine

Kata #1: Vending Machine

Your task is to implement a piece of software for a vending machine that sells sweets. The machine accepts coins and must be capable of returning change. It is up to you to decide on how inserted coins and change that is given out are represented. Consider the following variations of this exercise:
  • Simplification: you have an unlimited number of coins of every kind
  • Realistic: the machine is loaded with coins at the beginning and you have a limit on the number of coins of every kind
  • More realistic: the machine adds the inserted coins to respective coin slots and uses them to serve further transactions
  • Even more realistic: the machine tries to optimize the way of giving out coins - if there is danger of giving out too many coins of kind A, and there are is surplus of coins of kind B, then more of B coins are used to produce change
  • Futuristic: the machine asks you to provide it with coins that would help it return the proper change
How would your implementation of vending machine react if the amount of money inserted were less than the price of the chosen chocolate snack?

Monday, February 25, 2013

Piotr's Less Obvious Advice on Google Mock: State maintenance

Google Mock provides several ways to maintain state inside mock objects. One way of implementing state maintenance is with SaveArg. Consider the following example.

We have a class Configurator, which allows a caller to set and get values of a parameter:

class Configurator
{
    public:

    virtual ~Configurator() {}

    virtual void setParamX(int n) = 0;
    virtual int getParamX() = 0;
};


And we have a class Client that calls Configurator's methods and it also has a method incParamXBy, that can be used to increase the current value of paramX by a certain value.

class Client
{
    public:

    Client(Configurator & cfg);
    virtual ~Client() {}

    void setParamX(int n);
    void incParamXBy(int n);
    int getParamX();

    private:

    Configurator & _cfg;
};

incParamXBy internally calls setParamX and getParamX on Configurator:

void Client::incParamXBy(int n)
{
    _cfg.setParamX(_cfg.getParamX() + n);
}

Let's assume that the initial value of paramX is A and that we want to increase paramX by B each time we call incParamXBy. Our expectation is that if incParamXBy is called for the first time, it will result in calling cfg.setParamX(A+B).
  • second call of incParamXBy(B) will result in calling cfg.setPAramX(A + 2*B)
  • third call: cfg.setPAramX(A + 3*B), and so on...

Interaction between Client and Configurator in this case is such that Client relies on Configurator (issues getParamX()) in order to correctly calculate the parameter for next setParamX() call. If we want to test Client object, we need a MockConfigurator that is able to remember its current value of the parameter we are increasing:

class MockConfigurator : public Configurator
{
    public:

    int paramX;
    int * paramX_ptr;

    MockConfigurator()
    {
        paramX = 0;
        paramX_ptr = &paramX;
    }
   
    MOCK_METHOD1(setParamX, void(int n));
    MOCK_METHOD0(getParamX, int());
};

MockConfigurator has a public member paramX. We will use paramX to store current value of the parameter. We could have put paramX outside of MockConfigurator, in the test code, but I think it makes more sense to bind the parameter with the object.

And now the test:

MockConfigurator cfg;
Client client(cfg);

int inc_value = 10;

//getParamX will be called a number of times.
//If it is called, we will return the value pointed to by paramX_ptr.
//Returning with ReturnPointee is necessary, since we need to have
//the actual (updated) value each time the method is called.

EXPECT_CALL(cfg, getParamX())
    .Times(AnyNumber())
    .WillRepeatedly(ReturnPointee(cfg.paramX_ptr));

//SaveArg stores the 0th parameter of the call in the value pointed to by paramX_ptr (paramX)
//expectation 3
EXPECT_CALL(cfg, setParamX(cfg.paramX + 3*inc_value))
    .Times(1)
    .WillOnce(DoAll(SaveArg<0>(cfg.paramX_ptr), Return()));
//expectation 2
EXPECT_CALL(cfg, setParamX(cfg.paramX + 2*inc_value))
    .Times(1)
    .WillOnce(DoAll(SaveArg<0>(cfg.paramX_ptr), Return()));
//expectation 1
EXPECT_CALL(cfg, setParamX(cfg.paramX + inc_value))
    .Times(1)
    .WillOnce(DoAll(SaveArg<0>(cfg.paramX_ptr), Return()));

client.incParamXBy(inc_value); //this will match expectation 1
client.incParamXBy(inc_value);
//this will match expectation 2
client.incParamXBy(inc_value); //this will match expectation 3

Is it the only way to maintain state inside a mock object? Of course not. First of all, we could have an equivalent test without maintaining state inside out mock object at all. We could have written all method calls and all expectations using pre-calculated values that we know validate Client's behaviour. The point is that state maintenance gives us more flexibility that may be advantageous in case we want to write a number of similar tests (e.g. test the same behaviour for a range of parameter values or test different behaviours that rely accessing value previously stored in a mock).

Secondly, we can always implement state maintenance by using Invoke. Calling another function or method allows us not only to an equivalent to SaveArg, but also more complex state maintenance cases.

See also