jeudi 16 juillet 2015

(how) should i write a test for a transaction?

I am new to rails and would appreciate feedback on my tests. Most of my work so far has mimicked the Hartl tutorial but now I have jumped the nest.

I have a service object to require that every time a List is created, a Quantity associated with that list is also created. There is a third model, Food, and List and Food are associated through Quantity via has_many :through.

I have completed this successfully (both in that it functions properly and all my tests pass). The tests that pass include valid/invalid list/quantity creation (four separate tests).

I want to write a test checking that when a list is created, a quantity too is created. I wrote such a test without much "real understanding" (as Hartl would say), and to my surprise, it passed.

I now have two questions:

  1. Is this test (which I consider a test of the transaction itself) necessary?
  2. If so, should it be written differently? Though it is passing, I am not sure if it is really testing anything or written well.

Thank you. I've included below:

  • the five tests,
  • the service object containing the transaction, and
  • the create method in the Lists controller that calls the service object.

I appreciate any advice!

Quantity integration tests (2):

class QuantitiesSignupTest < ActionDispatch::IntegrationTest

  test "invalid quantities information" do
    get addquantity_path
    assert_no_difference 'Quantity.count' do
      post quantities_path, quantity: { food_id:  "",
                               list_id: "",
                               amount:              ""
                               }
    end
    assert_template 'quantities/new'
  end  

  test "valid quantities creation information" do
    get addquantity_path
    assert_difference 'Quantity.count', 1 do
      post_via_redirect quantities_path, quantity: { list_id: 1,
                                            food_id: 1,
                                            amount: 2 }
    end
    assert_template 'quantities/show'
  end  
end

List integration tests (3, including the transaction test):

class ListsCreateTest < ActionDispatch::IntegrationTest

  test "invalid list creation information" do
    get addlist_path
    assert_no_difference 'List.count' do
      post lists_path, list: { days:  "a",
                               name: "a" * 141 }
    end
    assert_template 'lists/new'
  end 

  test "valid list creation information" do
    get addlist_path
    assert_difference 'List.count', 1 do
      post_via_redirect lists_path, list: {
                                            days: 2,
                                            name: "example list"
                                          }
    end
    assert_template 'lists/show'
  end

  test "valid list creation with quantity creation" do
    get addlist_path
    assert_difference 'Quantity.count', 1 do
      post_via_redirect quantities_path, quantity: { list_id: 1,
                                            food_id: 1,
                                            amount: 2 }
    end
  end
end

Transaction in service object:

class WriteList  

  def initialize(params)
    @params=params
  end 

  def write
    ActiveRecord::Base.transaction do
      food = Food.all.sample.id
      list = List.new(days: @params[:days], name: @params[:name])
      list.save!
      Quantity.create!(food_id: food, list_id: list[:id], amount: 1+rand(6))
      return list
    end
    rescue
      return List.new(days: @params[:days], name: @params[:name])
  end
end

create method in Lists controller that calls the service object:

def create
  @list = WriteList.new(list_params).write
  if @list.save
    flash[:success] = "A list has been created!"
    redirect_to @list
  else
    render 'new'
  end
end

Rails 4.2.3, Cloud9. Development database = SQLite3, production database = postgres heroku.

Aucun commentaire:

Enregistrer un commentaire