Saturday, January 22, 2011

Grails with Aptana Studio 3 on Mac OSX

Setting JAVA_HOME: (http://www.oreillynet.com/mac/blog/2001/04/mac_os_x_java_wheres_my_java_h.html )
setenv JAVA_HOME /System/Library/Frameworks/JavaVM.framework/Home

Setup Grails (http://www.grails.org/Installation)
git clone git://github.com/grails/grails-core.git
Set the GRAILS_HOME environment variable to CHECKOUT_LOCATION/grails-core
Add the $GRAILS_HOME\bin directory to your PATH environment variable
Go to the GRAILS_HOME directory and run: ./gradlew libs

In Aptana Studio Workspace
grails create-app grails-demo
New Project 'grails-demo'

Then in the grails-demo project
> grails run-app

Note that grails commands feel much slower than the equivalent ruby commands, and initial application startup is significantly slower. I actually was beginning to wonder if everything was working as the browser spun.. patience paid off and I was rewarded with the initial welcome page.

Also attempted to add some sort of groovy support, but without any real success. Java editor helps with syntax highlighting of terms in the groovy files, but is cluttered reporting other syntax and compile errors 'cause doesn't understand groovy.

Note that 'natures' do report several groovy natures, but these do not appear to be associated with any file types.

Saturday, January 15, 2011

Rails - Iteration E3 -Fixture tests for prices

Need further study: http://api.rubyonrails.org/classes/Fixtures.html

When I tried to follow simple example e.g.

one_quantity_two:
product_id: one
cart_id: 2
quantity: 2

line_item.product was a nil object.

The format that did work

one_quantity_two:
product_id: <%= Fixtures.identify(:one) %>
cart_id: 2
quantity: 2

Most likely culprit --> rails/ruby version?

Iteration E2: Functional Test for bad cart

test "should redirect on invalid cart" do
get :show, :id => 'wibble'
assert_redirected_to store_path
assert_match flash[:notice], "Invalid cart"
end

TBD: use internationalized error message?

FYI - cause of the critical bug?

bad --> @line_item = @cart.add_product(:product.id)
good --> @line_item = @cart.add_product(product.id)

First case not passing id, instead passing (I think) an object reference! gotta love those one character typos!

Rails - Iteration E1 - line_item aggregation starts new

Take 2 on smarter cart!

First: add a unit test for the cart.add_product method

test "cart aggregates line items" do
c = carts(:one)
assert_equal 0, c.line_items.count, "cart items not empty at start of test"
p = products(:ruby)
item = c.add_product(p.id)
assert_equal 1, c.line_items.count, "first product add did not create new line item"
assert_equal 1, item.quantity, "new item quantity not 1"
item = c.add_product(p.id) #hold reference for future testing
assert_equal 1, c.line_items.count, "readd product caused increase in line items count"
assert_equal products(:ruby).id, item.product.id, "a problem with product id between line item and orig"
end

(Note to self: originally tried to do above like:
- assert_difference('c.line_items.count') do
- p = products(:ruby)
- c.add_product(p.id)
- c.save
- end
Note that the assert_difference requires a DB save event. Decided I didn't like that extra dependency on a unit test. Also note that the assert_difference requires a string not an object expression.)

Second: modify line_item_controller test to show aggregation of line items

test "should create/update line_item" do
#original test when just creating new items (iteration D)
assert_difference('LineItem.count') do
post :create, :product_id => products(:ruby).id
end
assert_redirected_to cart_path(assigns(:line_item).cart)
#new test - just repeat old and this time no_difference
assert_no_difference('LineItem.count') do
post :create, :product_id => products(:ruby).id
end
assert_redirected_to cart_path(assigns(:line_item).cart)

now when I complete the line item tests everything (including listing of cart after add) works as intended.

Rails - Iteration E1 - recovery from new defect introduced

Interesting, at end of last class all of my tests passed, but today I test my app and find that I have a critical defect!

Post /lines_items?product_id=4 fails horribly when trying to show the cart page with updated list.
Cart page complains about no 'title' attribute for a nil object
/line_items shows that my cart now has a line item for a product id 123456 <- which of course doesn't exist.

Old instincts: well time to add a check for null products and skip processing anything won't work.
New TDD instincts: Whoa! how can all my tests be passing? Why is the product id changing on add_product?

Step 1: Recreate the defect in a test.
Looks like my line_items_controller_test only confirms line item addition and redirect to cart page. But defect manifest at cart page....
Decided to try my hand at 'integration' test, since now testing flow from one controller to another.
> rails generate integration_test user_cart_session_test

Then add test method to the resulting skeleton:

test "line item adds to cart" do
item = products(:ruby)
post "/line_items", :product_id => item.id
follow_redirect!
assert_response :success
end

> rake test:integration --> Same problem as reported in the app!

Last Step: Rollback to a clean branch of code and start lesson over.

> git commit -a -m "test for my broken code"
> git checkout master
> rake test --> lots of problems? Wait the DB was mucked with
> rake db:drop
> rake db:migrate
> rake test --> ah! that's better!
> git checkout class.chapter10 test/integration/ --> pull over my new fangled test
rails test --> look now it's passing, got rid of my bug!
git add test/integration/
git commit -m "adding a functional test for cart and line items"

Note To Self: never ever forget to branch when starting new development! Love this cycle
1) break code unexpectedly
2) build test to reproduce break
3) revert code, import test and start dev over again (and always have access to previous work!)

Wednesday, January 5, 2011

Rails4 - Iteration D3 - functional tests for new cart button

When building the store page, we went through several examples of adding functional tests to confirm the store index page contained expected page elements. Seemed logical to extend these existing tests to track the addition of the cart button. In doing so learned a couple of interesting features of assert_select

1) use a block to test that each .entry now displays button "Add to Cart"
assert_select '.entry' do
assert_select '.button_to input[value=?]', /Add to Cart/
end

2) check that each form for Add to Cart contains the product_id information, in this case using a substitution marker ? to check the action contents.
assert_select '.entry form[action=?]', /.*product_id=\d+.*/

Note: the substitution regex did not recognize partial matches. For example, /product_id=\d+/ failed to find any elements because 'product_id' is only a partial match to the actual action value /line_items?product_id=4 needed to add .* at start and end to pad out for the remaining action text.

Note for future study: How do I put variables into the regex? for example might be nice to check that the action also contains correct target 'line_items' but I don't really want to hard code that. Instead want to test with line_items_path variable?