My shopping cart application is coming right along. I can add items and the total price seems to be accurate. However, while I was playing around with my new cart I noticed a very strange problem. I was playing around with the idea of allowing discounts to be applied to a cart as just additional items that would have a negative price. So while I am playing around with this idea I notice that the math isn't always adding up. If I start with an item that is $100 and then add a discount that is $81.40 I see that the total price isn't adding up to $18.60. This is definitely problematic After doing some further research, I realize I made a silly mistake. I am just using simple floats to calculate the costs. Floats are by nature inacurrate. Once you start using them in mathematical operations they start to show their inadequacy for precision. In keeping with the test driven method of creating code I need to create a unit test that shows this flaw.


You can see that I added another test method that uses actual floats for some of the prices as opposed to round numbers. Now when I run my test sweet I can see the fantastic floating point issue.


Once you get over the strangeness of 38.6 not equaling 38.6 I want to discuss streamlining test cases with you. You will notice that the code in ShoppingCartTest::testGetSubTotalWithPrecision() contains almost all duplicate code when compared to ShoppingCartTest::setUp(). If I were to continue following this pattern of doing things I would eventually have tests that are difficult to maintain. Phake allows you to very easily override stubs. This is very important in helping you to reduce duplication in your tests and leads to tests that will be easier to maintain. To overwrite a previous stub you simply have to redefine it. I am going to change ShoppingCartTest::testGetSubTotalWithPrecision() to instead just redefine the getPrice() stubs.


If you rerun this test you will get the same results shown in Example 2.7, “ShoppingCartTest Output”. The test itself is much simpler though there is much less unnecessary duplication. The reason this works is because the stub map I was referring to in the section called “How Phake::when() Works” isn't really a map at all. It is more of a stack in reality. When a new matcher and answer pair is added to a mock object, it is added to the top of the stack. Then whenever a stub method is called, the stack is checked from the top down to find the first matcher that matches the method that was called. So, when I created the additional stubs for the various Item::getPrice() calls, I was just adding additional matchers to the top of the stack that would always get matched first by virtue of the parameters all being the same.