How to get a locale specific date time value in C++
setlocale is your buddy here. There are sub categories - constants prefixed with LC_. You can change the locale for just date time for example.
setlocale when called with a NULL value for the second param returns the current locale set for the category [first param]
For different format strings, check MSDN for "strftime". %c, %x are formatstrings that take current locale into consideration.
This code snippet runs under VS20005. Tweak as per taste..
e.g. If you modify your locale - Control Panel > Regional Settings > Locale / Language to French
CString sCurrentLocale = setlocale(LC_ALL, NULL);
setlocale(LC_ALL, "");
CString strCurrentTime = CTime::GetCurrentTime().Format(_T("Generated : %#c"));
// produces "Generated : jeudi 31 janvier 2008 20:21:07"
setlocale(LC_ALL, sCurrentLocale );
strCurrentTime = CTime::GetCurrentTime().Format(_T("Generated : %#c"));
// produces "Generated : Thursday, January 31, 2008 20:23:08"
Show Me The Money-8.2 - Round 2 with fitnesse
!define COMMAND_PATTERN {ruby -I %p "L:/ruby_home/lib/ruby/gems/1.8/gems/fit-1.1/bin/FitServer.rb" -v}Ok so let’s run this. The table looks self-explanatory. We are adding three credit entries and verifying the balance. Now that reminds us we didn’t implement the currentBalance tracking part! Make a note of that Ok so let’s write the Fit fixture code.
!path "L:/Gishu/Ruby/Rails/ShowMeTheMoney"
# Lucky Charm : Sample Test Fixture to check if Ruby FitServer is reachable
!|eg.ArithmeticFixture|
|x|y|+|-|*|/|
|1|1|2|0|1|1|
!|fit.ActionFixture|
|start|AcceptanceTests.EnterInflowRecords|
|enter|inflow|PayDay|5000|
|check|currentBalance|5000|
|enter|inflow|Interest|1000|
|check|currentBalance|6000|
|enter|inflow|PayDay|5000|
|check|currentBalance|11000|
file: ShowMeTheMoneu\AcceptanceTests\enter_inflow_records.rb
module AcceptanceTests
class EnterInflowRecords < Fit::Fixture
def inflow dateCreated, sDescription, fAmount
end
def inflow= inflowObject
end
def current_balance
return 0
end
end
end
Now click on test in the wiki. It says inflow= method is called but missing. Strange. I add some trace lines to figure out what is going on. Turns out the inflow= method is being called with only the description param. It looks to me that that there can only be a max of three columns ever in an action fixture table. Let’s modify our test table like this!|fit.ActionFixture|So now lets get that fixture working
|start|AcceptanceTests.EnterInflowRecords|
|enter|description|PayDay|
|enter|amount|5000|
|press|addEntry|
|check|currentBalance|5000|
|enter|description|Interest|
|enter|amount|1000.50|
|press|addEntry|
|check|currentBalance|6000.50|
|enter|description|PayDay|
|enter|amount|5000|
|press|addEntry|
|check|currentBalance|11000.50|
Whoa! Lot of code there.require File.dirname(__FILE__) + '/../test/test_helper'
require 'inflow_controller'
require 'fit/fixture'
class RailsHelper < Test::Unit::TestCase
def setup
@controller = InflowController.new
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
end
def test_dummy
end
end
module AcceptanceTests
class EnterInflowRecords < Fit::Fixture
attr_accessor :description, :amount
def initialize
@helper = RailsHelper.new("test_dummy")
@helper.setup
end
def addEntry
@helper.get :new
@helper.post :create, :credit => {:description => @description, :amount => @amount}
end
def current_balance
return Credit.count
end
end
end
- Since Rails has spoilt me.. I resorted to sneaky ways to glue my application code to the Fit table. The get and post methods are added to the Test::Unit::TestCase by Rails. Since our fixture has to inherit from Fit::Fixture, I turned to composition.. created a dummy test case derivation as a member of the fixture. Distilled out the essential things.. and it works!
- Also current_balance as of now returns number of records in Credit table so that we know if the deal is going through (not what it should be doing but we will get to that).
We’re seeing that record count is 2 + expected. We have 2 records in our fixture. Is that it ? A trace says Yes. So we stick in a Credit.delete_all in the test helper setup and we’re good! Now lets go after the current_balance implementation. We don’t have a controller page for it. For now let’s do the simplest thing that works… keep it in Credit itself as a class method. This test took me sometime.. I used assert_equal initially, then made a detour into coercing both arguments to same value and finally reached : ‘Remember when comparing 2 float values, use assert_in_delta’. Now it looks simple
file: \ShowMeTheMoney\test\unit\credit_test.rb
DELTA = 0.001 #tolerance
def test_currentBalance
assert_in_delta totalAmountOfAllCreditEntries, Credit.currentBalance, DELTA, "Imbalance"
test_create
assert_in_delta totalAmountOfAllCreditEntries, Credit.currentBalance, DELTA, "Imbalance"
end
def totalAmountOfAllCreditEntries
obResultModels = Credit.find_by_sql("select sum(amount) as totalAmount from credits")
obResultModels[0].attributes["totalAmount"].to_f
end
file: \ShowMeTheMoney\app\models\credit.rb
def Credit.currentBalance
fCurrentBalance = 0
Credit.find(:all).each{|entry| fCurrentBalance += entry.amount}
fCurrentBalance
end
Ok now let’s get that acceptance test to pass. We correct current_balance method in enter_inflow_records.rb
def current_balance
Credit.currentBalance
end
And just like that Balboa lands one. Our first passing acceptance test!!
Next we can go on to implement the RowFixture table. But before that we need to incorporate deletes also into the above table. Hmm we need to spend more time thinking about our acceptance tests. We add some more steps to the above table to simulate the user choosing to delete the last record (hey everyone makes mistakes) and verifying that the current balance is still correct.
!|fit.ActionFixture|
|start|AcceptanceTests.EnterInflowRecords|
…
|check|currentBalance|11000.50|
|enter|select_entry|3|
|press|delete|
|check|currentBalance|6000.50|
We add some more steps to the above table to simulate the user choosing to delete the last record (hey everyone makes mistakes) and verifying that the current balance is still correct. We update the fixture code to deal with the new steps.
This gave me a bit of a fight.
- I initially used selectEntry as the table method to mark a record for deletion. Creating accessor :select_entry => undefined method ‘selectEntry’. Creating an accessor :selectEntry didn’t work => fit server wasn’t able to find select_entry=. In the end I just settled with select_entry in the html table.
- I initially implemented delete as shown below. This didn’t work – the record was not deleted.
def delete
@helper.post :destroy, :id => @select_entry.to_i
end
Little spying around lead to ‘Record#1 doesn’t mean id#1’ Well that just skipped my mind. However that’s a good thing coz we now have another test that we missed – trying to delete a record via manually editing the url. Make a note. I add the Record# to Record id lookup and..
def deleteTa da!
@helper.post :destroy, :id => getID_ForSelectedEntry
end
def getID_ForSelectedEntry
obSelectedEntry = Credit.find(:all, :order => "id")[@select_entry.to_i - 1]
obSelectedEntry.id
end
Show Me The Money-8.1 - Finishing up validation
Lets look at our iteration burndown. No points earned since we are still not complete.. we have Deleting Credit Entries and some UI polishing to do.
It shows that
- Unless there is a time warp in the near future, we aren’t going to make it.
- Do we have a problem. We aren’t going as fast as we hoped to. (The light trendline. Found Chart > Add Trendline… in Excel. Yay!). We could attribute some of that to the new tools and their learning curves.
We need to write the controller tests for validations. Test first as ever… rails doesn’t let us do much… it’s all taken care of! I’m coining a term for that -- ATCO
file: \ShowMeTheMoney\test\functional\inflow_controller_test.rb
def test_createEntryWithNoDescription
[nil, " "].each{|value|
test_new
post :create, :credit => {:description => value, :amount => 120.23 }
assert_response :success
assert_template 'inflow/new'
assert_errors_on_page
assert_equal @numberOfFixtureRecords, Credit.count
}
end
def test_createEntryWithNilZeroOrNegativeAmount
[nil, 0, -4.5].each {|value|
test_new
post :create, :credit => {:description => "Salary", :amount => value }
assert_response :success
assert_template 'inflow/new'
assert_errors_on_page
assert_equal @numberOfFixtureRecords, Credit.count
}
end
assert_errors_on_page is a custom assertion added to test_helper.rb, that checks if there is an error div tag on the rendered view
file: \ShowMeTheMoney\test\test_helper.rb
class Test::Unit::TestCase
...
#custom assertions
def assert_errors_on_page
assert_tag :tag => 'div', :attributes => {:class => 'fieldWithErrors'}
end
end
All Green! So now we can move on to delete or destroy as Rails calls it. ATCO!!
file:\ShowMeTheMoney\test\unit\credit_test.rb
def test_destroy
assert_nothing_raised { getFirstEntry }
getFirstEntry.destroy
assert_raise (ActiveRecord::RecordNotFound) { getFirstEntry }
end
file: \ShowMeTheMoney\test\functional\inflow_controller_test.rb
def test_destroy
firstEntryID = credits(:salary_credit_entry).id
assert_nothing_raised { Credit.find(firstEntryID) }
post :destroy, :id => firstEntryID
assert_response :redirect
assert_redirected_to :action => 'list'
assert_raise(ActiveRecord::RecordNotFound) { Credit.find(firstEntryID) }
end
So there we have it. I think we have all we need for this story except the spiffy UI.
Show Me The Money-7 - At a Canter
Lets start with some ‘functional’ a.ka. controller RETRIEVE tests now. Rails at our service as always, has a test stub awaiting..
Whoa! Whole lot of default tests in there. Let me see if they pass out of the box. No. All 8 fail with exceptions.
Lets comment out all the tests and take them one at a time. Lets take the functionality of listing existing records first to the block..
file:ShowMeTheMoney\test\functional\inflow_controller_test.rb
class InflowControllerTest < Test::Unit::TestCase
fixtures :credits
def setup
@controller = InflowController.new
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
end
def test_list
get :list
assert_response :success
assert_not_nil assigns(:credits)
assert_equal 2, assigns(:credits).size
assert_template 'list'
end
…
To run my tests, I’m going to switch to rake. So I type in rake at the project dir and it’ll run all my model and controller tests they say. And it’s true! All Green!
Ok. Next we test if the default index action redirects to list. For that we just uncomment the test_index default test, which checks if the controller “does a list” when the index method is invoked. Green!
Now we move on to ADD.
First we verify the new action by uncommenting default test_new. Green!
Next we verify if we can add a new test by uncommenting test_create. Borriinng! This isn’t fair Rails is taking the fun outta this by doing everything… even writing my tests. I might as well watch some TV if I’m not needed here. Red! We have a red.. seems like it’s time to call in.. ME!
All Green! Spent 5 mins trying to determine the id of the newly created record.. before resorting to SQL to help me get the new record itself.
Let’s take a break!
def test_create
test_new
numberOfCreditEntries = Credit.count
sDescription = 'my bank'
fAmount = 250000
post :create, :credit => {:description => sDescription, :amount => fAmount}
assert_response :redirect
assert_redirected_to :action => 'list'
assert_equal numberOfCreditEntries + 1, Credit.count
obCreditEntry = Credit.find( :first, :order => 'id DESC')
assert_equal sDescription, obCreditEntry.description
assert_equal fAmount, obCreditEntry.amount
end
VALIDATION
Alright, but what about the devious user’s who shall try to break our sacred system. What if he tries to save with no description or.. no amount?
So we write our concern as a model Test in credit_test.rb
def test_saveWithNoDescriptionFails
obCredit = Credit.find(1)
obCredit.description = " "
assert !obCredit.save, "Record saved without description!"
assert_equal 1, obCredit.errors.count
assert_equal "X", obCredit.errors.on(:description)
end
Red! The “X” is to check what the std error message is for validates_presence_of validator on the console when the test fails.
1) Failure:So we add our tiny line to the Credit class
test_saveWithNoDescriptionFails (CreditTest) [test/unit/credit_test.rb:37]:
Record saved without description!.is not true.
3 tests, 12 assertions, 1 failures, 0 errors
class Credit < ActiveRecord::Base
validates_presence_of :description
end
The next run tells us that the correct error message is “can’t be blank”. Obvious.. sheesh! Update our test. Green!
One more to check that amount is numeric, another to test that the amount is always positive. We also extracted a method to fetch the first record.
Adding the Is positive test broke the earlier Is numeric test. But a little tweaking and we’re in the green
file: ShowMeTheMoney\test\unit\credit_test.rb
def test_saveWithNoAmountFails
obCredit = getFirstEntry
obCredit.amount = " "
assert !obCredit.save, "Record saved with non-numeric amount!"
assert_equal 1, obCredit.errors.count
assert_equal "is not a number", obCredit.errors.on(:amount)
end
def test_saveWithZeroAmountFails
obCredit = getFirstEntry
obCredit.amount = 0
assert !obCredit.save, "Credit of amount 0 saved"
assert_equal 1, obCredit.errors.count
assert_equal "should be greater than 0", obCredit.errors.on(:amount)
end
private
def getFirstEntry
Credit.find(1)
end
credit.rb
class Credit < ActiveRecord::Base
validates_presence_of :description
validates_numericality_of :amount
protected
def validate
if (errors.on(:amount).nil?) && (amount <= 0)
errors.add(:amount, "should be greater than 0")
end
end
end
What happens if amount is assigned a nil value? Modified saveWithNoAmountFails and confirmed that it is caught and handled with an error message. Revert.
End of Day7
Show Me The Money-6 - On Rails.. Toot! Toot!!
The Story So Far: Alright, its been rough weather.
But now we got all that behind us and we can TDD our way to the end of the first story. Yup we’re on rails! Well I get the book again and rush thru Mike Clark's most excellent Chap12."Task T: Testing" for the nth time.
First we need to clone the structure from dev database to our test database. We can reuse the sql file (smart move!)
>mysql money_test <db\Create.sql -u gishu -pWe take Creation of credit enties first. MVC.. Model first.
Rails being helpful as always should have already created the test class file when we generated the scaffold.
CREATE
Well lets see if we can write a test to add a new credit entry.. Some chipping away here n there and we have..
file: L:\gishu\ruby\Rails\ShowMeTheMoney\test\unit\credit_test.rb
require File.dirname(__FILE__) + '/../test_helper'
class CreditTest < Test::Unit::TestCase
#fixtures :credits
def setup
Credit.delete_all
end
def test_create
obCreditEntry = Credit.new
obCreditEntry.description = 'Payday'
obCreditEntry.amount = 5000
assert obCreditEntry.save, obCreditEntry.errors.full_messages.join("; ")
assert_equal 1, Credit.count
obCreditEntry.reload
assert_not_nil obCreditEntry.id
assert_not_nil obCreditEntry.created_at
assert_equal 'Payday', obCreditEntry.description
assert_equal 5000, obCreditEntry.amount
end
end
- first I had to comment out the fixtures directive because we are not using it yet. And it was blowing up with some exception on a test run. (Later found out it was due to the default fixture file was incomplete)
- The setup method blows away all the records in our table.
- test_create first adds a record, reloads the record data and verifies the create operation. All set for a test run
L:\Gishu\Ruby\Rails\ShowMeTheMoney>ruby test\unit\credit_test.rbHey! We did not have to do anything to make it pass. Rails made the code pass. Anyway we should refactor – value duplication in the test. Introduce local vars
Loaded suite test/unit/credit_test
Started
.
Finished in 0.157 seconds.
1 tests, 6 assertions, 0 failures, 0 errors
sDescription = 'Payday'
fAmount = 5000
RETRIEVE
Lets write one to verify that we can retrieve multiple stored records. Although it is taken care of by the previous test.. lets write one to be sure.
This time we will use Rails fixtures i.e. YAML (text) files whose contents are loaded into the test database for snappy testing.
So let’s edit it (auto-created like most things in Rails). Make sure you don't use tabs and indent using spaces.
file: L:\gishu\ruby\Rails\ShowMeTheMoney\test\fixtures\credits.yml
salary_credit_entry:
id: 1
created_at: 2008-01-19 00:00:00
description: salary
amount: 15000
interest_credit_entry:
id: 2
created_at: 2008-01-20 00:00:00
description: interest
amount: 1000.50
You uncomment the magic-drippin’ line, which blows away the test DB, adds the two new records and loads them up into instance variables for us to use
def test_retrieve
obCredit = Credit.find(1)
assert_kind_of Credit, obCredit
assert_equal @salary_credit_entry.id, obCredit.id
assert_equal @salary_credit_entry.description, obCredit.description
assert_equal @salary_credit_entry.amount, obCredit.amount
assert_equal @salary_credit_entry.created_at, obCredit.created_at
end
And we need to comment out the existing setup and test_create methods temporarily – they need to be updated to work with the rails fixture. So lets run the test case
test_retrieve(CreditTest):Some console trace lines later, I find that the records are being added to the test DB but the @credits hash and @salary_credit_entry are nil. NO! That can't be... the book says otherwise.
RuntimeError: Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id
test/unit/credit_test.rb:33:in `test_retrieve'
I’m beginning to think this project is jinxed.. however a little sleuthing turns this Mike Clark’s (most excellent again) post up … Change in Rails defaults (test_helper.rb) again!
Apparently they switched on transactional fixtures and removed auto-created instance variables to make the unit tests go faster.
We can (always configure and) turn them back on using
Update our test cases like this (and I didn’t need the _before_type_cast tricks like the book says)
def test_retrieve
obCredit = Credit.find(1)
assert_kind_of Credit, obCredit
assert_equal credits(:salary_credit_entry).id, obCredit.id
assert_equal credits(:salary_credit_entry).description, obCredit.description
assert_equal credits(:salary_credit_entry).amount, obCredit.amount
assert_equal credits(:salary_credit_entry).created_at, obCredit.created_at
end
That passes. Now to get the first test to work with fixtures.. we don’t need the setup method and I update the expected record account to 1 + 2 fixture records. That's all - ALL GREEN!
Show Me The Money-5 - Feeling lucky today??
Hmmm... I'm not getting the right vibe from our acceptance test. An inflow entry would have a Date and a Description in addition to the amount. Our AccTest does not seem to indicate that.
Seems like we should be replacing our current table, with an ActionFixture+RowFixture combo. (Not its not a ploy to get the remaining fixture types into this example.)
An ActionFixture would simulate how the user would use an imaginary system, adding records one at a time.
The RowFixture would verify that all the inflow records have been persisted. Hmm.. I’ll quickly write up the tables and write the fixtures later post implementation of this feature. (I know I’ll be ambushed again. I’m gonna lie on the couch and get my strength back.. too much fitnesse for now.)File: http://localhost:2345/ShowMeTheMoneyMain.TestsForTrackingInflowsS6
!define COMMAND_PATTERN {ruby -I %p "L:/ruby_home/lib/ruby/gems/1.8/gems/fit-1.1/bin/FitServer.rb" -v}Let take a look at our schedule..
!path "L:/Gishu/Ruby/Rails/ShowMeTheMoney"
# Lucky Charm : Sample Test Fixture to check if Ruby FitServer is reachable
!|eg.ArithmeticFixture|
|x|y|+|-|*|/|
|1|1|2|0|1|1|
#!|AcceptanceTests.TestTrackInflows|
#|amountReceived|currentBalance()|
#|100|100|
#|500|600|
#|1200|1800|
!|fit.ActionFixture|
|start|EnterInflowRecords|
|enter|inflow|2008-01-13|PayDay|5000|
|check|currentBalance|5000|
|enter|inflow|2008-01-15|Interest|1000|
|check|currentBalance|6000|
|enter|inflow|2008-02-13|PayDay|5000|
|check|currentBalance|11000|
!|GetInflowRecords|
|receivedOn|description|amount|
|2008-01-13|PayDay|5000|
|2008-01-15|Interest|1000|
|inflow|2008-02-13|PayDay|5000|
We get 1 point each for 'Iteration planning',‘Setting up Fitnesse’ and ‘Write Acceptance Tests’. Making the tests pass would be part of the implementation task.
Burndown charts are brutally honest. The Y axis shows ideal hours pending (We now have 13 ideal hours of work left in this iteration) The X axis shows days into the iteration (We are at end of Day 4). We can easily create one from our iteration plan and the items we have completed.
As of now looks like we'll slightly overshoot.
So lets get cracking.. I’m upbeat.. feeling lucky today
First thing, the UI. The inflow record as mentioned before has 3 fields. From the CRUD (Create, Retrieve, Update and Delete) - we would need Create for sure. So lets start with that first.
Switch to our rails project dir.
First create our DB called money. Rails uses 3 DBs for different purposes as shown below.
I’m sloppy and impatient. After some mistakes and furious rectification.. Now I have to drop the Db and create it again. This time, we’ll put in a text file to save typing if something like this happens again.
File: ShowMeTheMoney/db/CreateDB.sql
drop database if exists money_development;
drop database if exists money_test;
drop database if exists money_production;
create database money_development;
create database money_test;
create database money_production;
grant all on money_development.* to 'gishu'@'localhost' identified by 'kaChing';
grant all on money_test.* to 'gishu'@'localhost';
grant all on money_production.* to 'gishu'@'localhost';
Now lets create the table. We’ll call it ‘credits’. So once again, we create a file DB\Create.sql like in the book.
File: ShowMeTheMoney/db/Create.sql
drop table if exists credits;Note: created_at is a special name which will get Rails to update that column auto-magically with the time of record creation. See Pg 227 of AWDWR First Ed
create table credits (
id int not null auto_increment,
created_at datetime not null,
description varchar(100) not null,
amount decimal(10,2) not null,
primary key (id)
);
Next get it into the db, at the command prompt
- >mysql -u gishu -p money_development
File: ShowMeTheMoney/db/config.yml
development:Now we run the Rails generate script to auto-create our classes. Rails 2.0.2 says it needs gem 0.9.4+ So lets get in from the online store
adapter: mysql
database: money_development
host: localhost
username:
password:
- >gem update --system
- >ruby script/generate scaffold Credit Inflow
Now it says --- "wrong number of arguments (1 for 2)"
We’re nearing the straw that will break this camel’s back. It’s times like these I’m relieved I don’t have a gun. Google Google.. Oh my god Rails 2.0 has real sharp horns – so much for ‘No surprises’. Scaffolding has been banished to an on-demand plugin! The only good blog-post (by Fairleads) I find recommends going back to 1.2 if you need to work with old tutorials / books etc.
Since I don't have the luxury of learning rails 2.0 just yet... You don’t have to ask me again.. Excuse me while I rollback my dev environment. Rails 1.2.6 it is. Install, create project, run scaffold generator.
“Can't connect to MySQL server on 'server' (10061)”
Just Great ! I guess I wasn’t that lucky today after all.
MySql though has great docs - http://dev.mysql.com/doc/refman/5.0/en/can-not-connect-to-server.html
Trying all those diagnostic steps showed me a diff. My port setting is 3307 not 3306 as in the doc. Edit database.yml, Add port: 3307 to all 3 groups. Restart Webrick.
Run scaffold generator again. Done. Browse to http://localhost:3000/Inflow and I can See! I can see the blessed view!!
Phew! That's it for today.. .
Show Me The Money-4 - Light at the end of the AccTest Tunnel
The day is lost.. after quite a bit of grappling with RubyFit and Fitnesse.. all I get is 2 Exceptions and some command line output captured.. and I don’t see what the problem is. Error reporting has scope and need for improvement.
[I switch OFF the project clock. Overtime.. just this once!!]
Time to hit the forums after lots of fiddling with the paths and what nots.. (Days pass waiting for someone to answer … no answers.)
Let me go over the material that I have again with a fine-comb. First stop Ron’s article. Most of it looks ok.. I’m doing it right. Wait.. the wise ron has worked in small steps.. He has a small wiki table to test something that comes along with the Ruby Fit Server implementation. So if that thing turns out green, I can be assured that Fitnesse is able to talk to my copy of Ruby FitServer. So I copy the table right out of Ron’s article and paste it into my Fitnesse test page..
!define COMMAND_PATTERN {ruby -v -I %p "L:/ruby_home/lib/ruby/gems/1.8/gems/fit-1.1/bin/FitServer.rb"}
!path "L:/Gishu/Ruby/ShowMeTheMoney"
!|eg.ArithmeticFixture|
|x|y|+|-|*|/|
|1|1|2|0|1|1|
!|AcceptanceTests.TestTrackInflows|
|amountReceived|currentBalance()|
|100|100|
|500|600|
|1200|1800|
Save and Click the test button and lets see what happens.. fingers crossed.
I take a crack at it the next day. I scan material on the Ruby FitServer’s home page http://fit.rubyforge.org/basics.html and BAM!
“In RubyFIT, that also is the name of the file containing the fixture, where the camel cased words are lied without capital letters and separated by underscores. Programmers can start creating a file named calculate_discount.rb and writing the skeleton of the CalculateDiscount fixture:”
Both Ron and Cory used one-word fixture names like People and Division… they don’t call em experts for nothing. RubyFit like Rails uses this internal conversion scheme of converting camelCase words to camel_case words
So I quickly go and rename my Ruby File from TestTrackInflows to test_track_inflows.rb
Click Test and now I get an error saying that my method ‘amount_received=’ is undefined. Ahh.. more of the same. Change the method names so that we have…
require 'fit/column_fixture'
module AcceptanceTests
class TestTrackInflows < Fit::ColumnFixture
attr_reader :balance
attr_accessor :amount_received
def initialize
@balance = 0
end
def current_balance
@balance
end
end
end
Re-test and we have red-hot ignition! WooHoo… please excuse me while I do that once again. WOO HOO !!!
It’ll be a while till I glue my application code to the test-table. So we’ll fake out the first result and see if we get a small green.. just to keep our spirits high. Sneaky tweak to the fixture methoddef current_balance
Sure enough!! We have a green. Rollback that temp hack.
#@balance
100
end
Its time.. to do the victory jig.
Update:
Iteration#1 : Day 4/10
I’m penalizing one day to reflect reality. I did spend an awful amount of time trying to get all this running.
Show Me The Money - 3 - Fitnesse + Fit + Ruby oh my!
Iteration#1 Day 2/10
Voice of Customer (VOC) : Basically I'd be getting bags of money from different sources and it should add up to my current balance
Is that detailed enough? Lets find out by writing some executable specs a.k.a. acceptance tests to expose any hidden reqs. For that we need to get Fitnesse running with Ruby. That's another non-story task that we have. We already have fitnesse downloaded last time. Now we need to install a FitServer for Ruby.
- d:\>gem install fit
Next create a Main page for our Acc tests. Edit the URL to "http//localhost:2345/ShowMeTheMoneyMain"
Now click on the link show to create this page. Now I need to add a comment - a quick search gets me this page. Yes the Fitnesse wiki has a Search button on the left just like Edit.. its not seen on the online version (to prevent web spiders apps) but its activated on your local copy of the wiki pages. I need to prefix the line with a # for a comment. Lets call the first page. TestsForTrackingInflowsS6. So we type that in and hit Save.
#This is the Main Page with links to all the acceptance tests for the app to track my money betterNow before we create the TestsForTrackingInflowS6 subwiki page, We need to mark this page as a Test Suite. We do that by opening up the page Properties (Button on the left), check the Suite property and click ‘Save Properties’. Now we click on the question mark link after the TestsForTrackingInflowsS6 to create the subwiki page. Here’s where we start writing our tests. VOC: Well its pretty simple, Every time I receive an amount, my current balance must be incremented by the same amount. Dev: Let me quickly write that up
#
# ShowMeTheMoney
# ^TestsForTrackingInflowsS6
!|TestTrackInflows|Dev: Is this what we mean ?
!|AcceptanceTests.TestTrackInflows|
|amountReceived|currentBalance()|
|100|100|
|500|600|
|1200|1800|
VOC: Yup.
Ok so I save the page. Bid adieu to the customer for now.
We also need to check the Test property in Page Properties. Wait a sec, its already showing a Test button – seems like subwiki pages under a suite page have their Test property set by default... Cool. Lets try clicking that shiny blue button.
Dirty Yellow. "Could not find fixture : AccTestTrackInflows"
Ok. So lets create that ruby fixture – the glue between the wiki tests and our application code. A ColumnFixture should do the trick. Hmm.. seems like the
Ruby variant has some quirks of its own.
- We need to rename the fixture as X.Y e.g.AcceptanceTests.TestTrackInflows.
- Create a directory called X e.g. AcceptanceTests and place the ruby class file under it.
- The class should be within a module under the same name as the parent folder - X has to be a module and Y a class within the module as seen in the example below
require 'fit/column_fixture'
module AcceptanceTests
class TestTrackInflows < Fit::ColumnFixture
attr_reader :balance
attr_accessor :amountReceived
def initialize
@balance = 0
end
def currentBalance
@balance
end
end
end
Next we need to make Fitnesse run the Ruby Fit Server instead of the default one that talks Java. This is the page we need to read for details. (Thanks Andy D.)
We need to define the COMMAND_PATTERN as follows
Now I need to help the Wiki page find the fixture. I do that with the following directive at the top of the TestTrackingInflowsS5 page.
!define COMMAND_PATTERN {ruby -I %p "L:\ruby_home\lib\ruby\gems\1.8\gems\fit-1.1\bin\FitServer.rb" -v}
!path "L:\Gishu\Ruby\ShowMeTheMoney"
But the darn thing won’t work.
[Update: Cory Foy found out that the -v option must be at the "end" of the COMMAND pattern. See http://www.nabble.com/Re%3A-Re%3A-Trouble-getting-Fitnesse-to-play-with-Ruby-FIT-server-p14782769.html
]
Show Me The Money - 2
the book mentioned a project named DamageControl but that looks like it has closed shop for now. Some more surfing... CIA.. Cerebrus.. CruiseControl.rb aha!
I download the latest cruisecontrolrb-1.2.1.tgz, that along with the Getting Started page
was all that I needed.
I created a rails project on my machine with
- l:\Gishu\Ruby>rails ShowMeTheMoney
- l:\Gishu\Ruby\ShowMeTheMoney> svn import -m "First Rails App into Version Control" svn://babybox/ShowMeTheMoney/trunk
- D:\cruisecontrolrb-1.2.1>cruise add ShowMeTheMoney --url svn://babybox/ShowMeTheMoney/trunk
- D:\cruisecontrolrb-1.2.1>cruise start
Crazy gem of activesupport won't load.. seems like it wont load the gem version that comes along with cruisecontrol.rb.. Precious time is lost reinstalling various components, trying mailing lists and basically trying to beat the thing into submission.
[Many days later.. inertia is a leech]
And I make the mistake of waiting for cc.rb to be operational. Suddenly one day on my way back from work.. I have a pair of stunning revelations just like that
#1: There is nothing to build like in C#/Java
#2: I only need a CIS to run all the tests and inform me if someone breaks the build. Since I'm the only one working, I just have to watch myself.
I can proceed without cc.rb working right now. Now wiser and 1 day of our iteration time later, I trudge on to start ‘delivering value’.. we gotta start with that sometime soon if we want to be 'agile'.
[Alexey V. spent some time trying to get a handle on this thing.. ruby versions, gem versions, stack traces,... all in vain.]
Show Me The Money - 1
I have trouble tracking my money. Frankly because it is too boring..
Some time back, I attended a leadership course that had a module on Finance.. and predictably I went through it like greased lightning.. I resolved to diligently go through those notes soon. Still haven't :)
Now that I know a bit about cashflow and balance sheets, I would like to create them.. and since it sucks the joy out of me.. I'd rather like someone else to do it for me... my computer. Nothing too fancy.. just basic stuff.
Around the same time, I get enchanted with Rails.. So it's time to put my knowledge to the sword. And since I don't want this to be too easy, I'm going to practice what I read in Mike Cohn's book on Agile Estimation.
So I'm going to try to be as agile as I possibly can and get a working application and lots of learning out of this. I christen this app - ShowMeTheMoney like Cuba Gooding yelled out in Jerry Maguire.
Since I do this in my personal off-office time, we need to scale down time units
1 day => 2 hrs of real time
1 Iteration (2 weeks - 10 days) => 20 hrs of real time
So I come with the list of stories for this app as seen in Sheet#1
I play a bit of "planning poker" (with myself due to constraints) to come up with the story point estimates.. Looks like 14 story points in all.
So quickly let's ask the customer (Me again) to see which ones is most important to him. I pick 6, 1 and 2 to allow me to enter receipts and expenditures as that constitutes a working product.
Lets break this down into itsy bitsy tasks first. Thats seen in Sheet 3. We come with an estimate of 27 ideal hrs including some project preparation tasks like setting up a build server.
I'd like to keep some slack since I'm dealing with new tech here. So we'd plan for 15 hours of work in the first iteration - 75% utilization. I choose to leave out of Story#2 - Group expenses by category for now; we'll have a usable app tracking my transactions and we can build in categorization later.
So we're aiming for 2 story points this iteration. This is our initial velocity. Dividing total number of story points (14) by velocity (2), gives us 7 iterations. Since this is the start of the project, we're not too confident of this estimate.. so it would be wise to state this estimate as a range - multiplying 7 by 0.6 and 1.6,
Release Plan
Our initial estimate is 4 to 11 iterations. We're not saying 4 or 11 but rather that it may take that much time. Only results from actual iterations will help us improve our estimate and narrow down this range.
[A few hours later]
I finished reading Pragmatic Project Automation and strafed again thru Pragmatic Version Control. Let's begin..