リファクタリング:Rubyエディションのサンプルのリファクタリング前とリファクタリング後の写経とtest/unitのテストコード

#Qiitaとrubyとtest/unitとリファクタリング初心者です！！

タイトル長いな...

リファクタリング:Rubyエディション読んで、サンプルコードを見つけて、
[リファクタリング：Rubyエディションの写経](https://github.com/snowmi/refactoring)を読んでて、開始時のサンプルコードとテストフレームワークのコードが見当たらなかったので書いた。テストコードは初めて書くから結構強引に書いた。
rspecも人気だけど、今回はテストはruby標準ライブラリのtest/unitで書いた。
コメントアウトは適宜外して動かしてほしい。
リファクタリング後のコードに差し替えると微妙に動かないところがあるので適宜書き換えが必要かも。html表示のテストは書いてない。
リファクタリングの経緯と変更点も追記するかもしれないし、しないかもしれない。

2017/08/27追記
ruby2.0以降requireがカレントディレクトリ明示して./testじゃないと動かないところを修正
minitest版も追記。minitestは$ sudo gem install minitestでインストールできる。minitestのほうがtest/unitより便利っぽい
 result = "Rental Record for #{@name}\n "の文末の謎のスペースを除去。ここでtest通らなかった。正しくは result = "Rental Record for #{@name}\n"。


```ruby:test.rb
#test.rb

class Movie
	REGULAR = 0
	NEW_RELEASE = 1
	CHILDRENS = 2

	attr_reader :title
	attr_accessor :price_code

	def initialize(title, price_code)
		@title, @price_code = title, price_code
	end
end

class Rental
	attr_reader :movie, :days_rented
	def initialize(movie, days_rented)
		@movie, @days_rented = movie, days_rented
	end
end

class Customer
	attr_reader :name

	def initialize(name)
		@name = name
		@rentals = []
	end

	def add_rental(arg)
		@rentals << arg
	end
	def statement
 	total_amount, frequent_renter_points = 0, 0

	result = "Rental Record for #{@name}\n"

	@rentals.each do |element|
	this_amount = 0

	# 各行の金額を計算
	case element.movie.price_code
	when Movie::REGULAR
		this_amount += 2
		this_amount += (element.days_rented - 2) * 1.5 if element.days_rented > 2
	when Movie::NEW_RELEASE
		this_amount += element.days_rented * 3
	when Movie::CHILDRENS
		this_amount += 1.5
		this_amount += (element.days_rented - 3) * 1.5 if element.days_rented > 3
	end

	# レンタルポイントを加算
	frequent_renter_points += 1
	# 新作2日間レンタルでボーナス点を加算
	if element.movie.price_code == Movie::NEW_RELEASE && element.days_rented > 1
		frequent_renter_points += 1
	end
	# このレンタルの料金を表示
	result += "\t" + element.movie.title + "\t" + this_amount.to_s + "\n"
	total_amount += this_amount
	end
	# フッター行を追加

	result += "Amount owed is #{total_amount}\n"
	result += "You earned #{frequent_renter_points} frequent renter points"
	result
	end
end

#リファクタリング後
=begin

# encodling:utf-8

# ----- Movieクラス ------
class Movie
  REGULAR = 0
  NEW_RELEASE = 1
  CHILDRENS = 2

  attr_reader :title
  attr_reader :price_code

  def price_code=(value)
    @price_code = value
    @price = case price_code
    when REGULAR; RegularPrice.new
    when NEW_RELEASE; NewReleasePrice.new
    when CHILDRENS; ChildrensPrice.new
    end
  end

  def initialize(title, the_price_code)
    @title, self.price_code = title, the_price_code
  end

  def charge(days_rented)
    @price.charge(days_rented)
  end

  def frequent_renter_points(days_rented)
    @price.frequent_renter_points(days_rented)
  end
end

# ----- DefaultPriceモジュール -----
module DefaultPrice
  def frequent_renter_points(days_rented)
    1
  end
end

# ----- RegularPriceクラス -----
class RegularPrice
  include DefaultPrice
  def charge(days_rented)
    result = 2
    result += (days_rented - 2) * 1.5 if days_rented > 2
    result
  end
end

# ----- NewReleasePriceクラス -----
class NewReleasePrice
  def charge(days_rented)
    days_rented * 3
  end

  def frequent_renter_points(days_rented)
    days_rented > 1 ? 2 : 1
  end
end

# ----- ChildrensPriceクラス -----
class ChildrensPrice
  include DefaultPrice
  def charge(days_rented)
    result = 1.5
    result += (days_rented - 3) * 1.5 if days_rented > 3
    result
  end
end

# ----- Rentalクラス -----
class Rental
  attr_reader :movie, :days_rented

  def initialize(movie, days_rented)
    @movie, @days_rented = movie, days_rented
  end

  # 金額を計算
  def charge
    movie.charge(days_rented)
  end

  def frequent_renter_points
    movie.frequent_renter_points(days_rented)
  end

end

# ----- Customerクラス -----
class Customer
  attr_reader :name

  def initialize(name)
    @name = name
    @rentals = []
  end

  def add_rental(arg)
    @rentals << arg
  end

  def statement
    result = "Rental Record for #{@name}\n"
    @rentals.each do |element|
      # このレンタルの料金を表示
      result += "\t" + element.movie.title + "\t" + element.charge.to_s + "\n"
    end

    # フッター行を追加
    result += "Amount owed is #{total_charge}\n"
    result += "You earned #{total_frequent_renter_points} frequent renter points"
    result
  end

  def html_statement
    result = "<h1>Rentals for <em>#{@name}</em></h1><p>\n"
    @rentals.each do |element|
      result += "\t" + element.movie.title + ": " + element.charge.to_s + "<br>\n"
    end

    result += "<p>You owe <em>#{total_charge}</em><p>\n"
    result += "On this rental you earned" + "<em>#{total_frequent_renter_points}</em> " + "frequent renter points<p>"
    result
  end
  private

  def total_charge
    @rentals.inject(0) { |sum, rental| sum + rental.charge }
  end

  def total_frequent_renter_points
    @rentals.inject(0) { |sum, rental| sum + rental.frequent_renter_points}
  end
end

=end


=begin

class Foo
   def foo
     "foo"
   end
   def bar
#     "foo"
     "bar"
   end
end

=end




=begin

jaws = Movie.new("Jaws", Movie::NEW_RELEASE)
et = Movie.new("ET", Movie::REGULAR)
anpanman = Movie.new("Anpanman", Movie::CHILDRENS)

first_rental = Rental.new(jaws, 3)
second_rental = Rental.new(et, 5)
third_rental = Rental.new(anpanman, 2)

snowmi = Customer.new("Snowmi")

snowmi.add_rental(first_rental)
 puts "----- Only first_rental -----"
 puts snowmi.statement

snowmi.add_rental(second_rental)
 puts "----- Add second_rental -----"
 puts snowmi.statement

snowmi.add_rental(third_rental)
 puts "----- Add third_rental -----"
 puts snowmi.statement

#puts "html section"
#puts snowmi.html_statement

=end
```


```ruby:test_test1.rb
require 'test/unit'
require './test'


=begin
class TC_Foo < Test::Unit::TestCase
  def setup
    @obj = Foo.new
  end

  # def teardown
  # end

  def test_foo
    assert_equal("foo", @obj.foo)
  end
  def test_bar
    assert_equal("bar", @obj.bar)
  end
end
=end


class Test1 < Test::Unit::TestCase
  def setup
		@jaws = Movie.new("Jaws", Movie::NEW_RELEASE)
		@et = Movie.new("ET", Movie::REGULAR)
		@anpanman = Movie.new("Anpanman", Movie::CHILDRENS)

		@first_rental = Rental.new(@jaws, 3)
		@second_rental = Rental.new(@et, 5)
		@third_rental = Rental.new(@anpanman, 2)

		@snowmi = Customer.new("Snowmi")
		@snowmi.add_rental(@first_rental)
		@snowmi.add_rental(@second_rental)
		@snowmi.add_rental(@third_rental)


		@str ="Rental Record for Snowmi
 	Jaws	9
	ET	6.5
	Anpanman	1.5
Amount owed is 17.0
You earned 4 frequent renter points"
  end

  def test_statement
		assert_equal(@str, @snowmi.statement)
  end
end
```


```ruby:minitest_test1.rb
#minitest_test1.rb
require 'minitest/autorun'
require 'minitest/unit'
require './test'

class TestFoo < MiniTest::Unit::TestCase
  def setup
        @jaws = Movie.new("Jaws", Movie::NEW_RELEASE)
        @et = Movie.new("ET", Movie::REGULAR)
        @anpanman = Movie.new("Anpanman", Movie::CHILDRENS)

        @first_rental = Rental.new(@jaws, 3)
        @second_rental = Rental.new(@et, 5)
        @third_rental = Rental.new(@anpanman, 2)

        @snowmi = Customer.new("Snowmi")
        @snowmi.add_rental(@first_rental)
        @snowmi.add_rental(@second_rental)
        @snowmi.add_rental(@third_rental)


        @str = "Rental Record for Snowmi
#{"\t"}Jaws#{"\t"}9
#{"\t"}ET#{"\t"}6.5
#{"\t"}Anpanman#{"\t"}1.5
Amount owed is 17.0
You earned 4 frequent renter points"
  end

  def test_statement
        assert_equal(@str, @snowmi.statement)
  end
end

```