ソフトウェアテスト
ソフトウェアテスト
https://service.shiftinc.jp/column/3621/
ソフトウェアをリリースする上で大切なことは、「不具合のない製品」を作ることです。不具合が多く使えない機能が多いことは、品質が悪い製品を意味します。このことから、ソフトウェアテストは不具合を発見し改善するために行います。
ソフトウェアテストの7原則
- 不具合があることしか示せない
- 全数テストは不可能
- 初期テスト
- 不具合の偏在
- 殺虫剤のパラドックス
- テストは条件次第
- 不具合ゼロの落とし穴
ソフトウェアテストの分類方法
品質によるソフトウェアテストの分類
ソフトウェアの品質とは?
品質特性 | 概要 |
---|---|
機能適合性 | 実装された機能がニーズを満たす度合い |
性能効率性 | システムの実行時の性能や資源効率の度合い |
互換性 | 他製品やシステムと機能や情報を共有、変換できる度合い |
使用性 | 効果的、効率的に利用できる度合い |
信頼性 | 必要時に実行できる度合い |
セキュリティ | 不正に悪用されることがなく、情報やデータが保護される度合い |
保守性 | 効果的、効率的に保守や修正ができる度合い |
移植性 | 効果的、効率的に他のハードウェアや実行環境に移植できる度合い |
品質を測るためのテストの具体例
- 機能テスト
- リクエスト通りに動作するかどうか
- 性能テスト
- 快適に使えるレスポンスの早さかどうか
- 負荷テスト
- 負荷の許容できる限界値を測る
- ユーザビリティテスト
- ユーザーが使いやすいかどうか
- セキュリティテスト
- 利用が安全かどうか
工程によるソフトウェアテストの分類
テスト計画
- テスト対象の決定
- テストのやり方の決定
- 役割分担の決定
- 準備対象の決定
- スケジュールの決定
- 管理方針の決定
テスト設計
- インプット情報の入手と確認
- テスト設計方針の決定
- テストケースの作成
テスト実行
- テスト環境の準備
- テストデータの準備
- 実行手順の確認
- ツールの準備
- 実行スケジュールの作成
- 実行
テストレベルによるソフトウェアテストの分類
ソフトウェアテストでは、まずそのソフトウェアの動作における最小単位でテストを行います。これを単体テスト、あるいはユニットテストと言います。
次に、複数の動作を組み合わせて結合テストを行います。結合テストでは連続する動作が正常に動くかどうかを確認します。
開発の終盤で行われるのが、ソフトウェアの全体の流れを確認するシステムテストです。システムテストでは、ソフトウェアだけでなくハードウェア部分も包括してテストを行います。
技法による分類
テスト技法で分類すると、ブラックボックステストとホワイトボックステストに分けられます。
ブラックボックスは「中身が見えない」という意味で、ブラックボックステストではソフトウェアの中身を見ずに、入力した内容に対して期待した出力があるかを確認します。
一方、ホワイトボックスではソフトウェアの中身も確認し、入力から出力の間にどのような処理が行われているかも併せて確認します。
引用リスト
ソフトウェアテスト
ソフトウェアテスト
https://service.shiftinc.jp/column/3621/
ソフトウェアをリリースする上で大切なことは、「不具合のない製品」を作ることです。不具合が多く使えない機能が多いことは、品質が悪い製品を意味します。このことから、ソフトウェアテストは不具合を発見し改善するために行います。
ソフトウェアテストの7原則
- 不具合があることしか示せない
- 全数テストは不可能
- 初期テスト
- 不具合の偏在
- 殺虫剤のパラドックス
- テストは条件次第
- 不具合ゼロの落とし穴
ソフトウェアテストの分類方法
品質によるソフトウェアテストの分類
ソフトウェアの品質とは?
品質特性 | 概要 |
---|---|
機能適合性 | 実装された機能がニーズを満たす度合い |
性能効率性 | システムの実行時の性能や資源効率の度合い |
互換性 | 他製品やシステムと機能や情報を共有、変換できる度合い |
使用性 | 効果的、効率的に利用できる度合い |
信頼性 | 必要時に実行できる度合い |
セキュリティ | 不正に悪用されることがなく、情報やデータが保護される度合い |
保守性 | 効果的、効率的に保守や修正ができる度合い |
移植性 | 効果的、効率的に他のハードウェアや実行環境に移植できる度合い |
品質を測るためのテストの具体例
- 機能テスト
- リクエスト通りに動作するかどうか
- 性能テスト
- 快適に使えるレスポンスの早さかどうか
- 負荷テスト
- 負荷の許容できる限界値を測る
- ユーザビリティテスト
- ユーザーが使いやすいかどうか
- セキュリティテスト
- 利用が安全かどうか
工程によるソフトウェアテストの分類
テスト計画
- テスト対象の決定
- テストのやり方の決定
- 役割分担の決定
- 準備対象の決定
- スケジュールの決定
- 管理方針の決定
テスト設計
- インプット情報の入手と確認
- テスト設計方針の決定
- テストケースの作成
テスト実行
- テスト環境の準備
- テストデータの準備
- 実行手順の確認
- ツールの準備
- 実行スケジュールの作成
- 実行
テストレベルによるソフトウェアテストの分類
ソフトウェアテストでは、まずそのソフトウェアの動作における最小単位でテストを行います。これを単体テスト、あるいはユニットテストと言います。
次に、複数の動作を組み合わせて結合テストを行います。結合テストでは連続する動作が正常に動くかどうかを確認します。
開発の終盤で行われるのが、ソフトウェアの全体の流れを確認するシステムテストです。システムテストでは、ソフトウェアだけでなくハードウェア部分も包括してテストを行います。
技法による分類
テスト技法で分類すると、ブラックボックステストとホワイトボックステストに分けられます。
ブラックボックスは「中身が見えない」という意味で、ブラックボックステストではソフトウェアの中身を見ずに、入力した内容に対して期待した出力があるかを確認します。
一方、ホワイトボックスではソフトウェアの中身も確認し、入力から出力の間にどのような処理が行われているかも併せて確認します。
引用リスト
【メモ】Railsでフォロー機能
Railsチュートリアル
https://railstutorial.jp/chapters/following_users?version=5.0
すなわち、CalvinはHobbesをフォローしていても、HobbesはCalvinをフォローしていないといった関係性が成り立つのです。このような左右非対称な関係性を見分けるために、それぞれを能動的関係 (Active Relationship)と受動的関係 (Passive Relationship)と呼ぶことにします。
relationshipテーブルを作る
$ rails generate model Relationship follower_id:integer followed_id:integer
class CreateRelationships < ActiveRecord::Migration[5.0] def change create_table :relationships do |t| t.integer :follower_id t.integer :followed_id t.timestamps end add_index :relationships, :follower_id add_index :relationships, :followed_id add_index :relationships, [:follower_id, :followed_id], unique: true end end
indexを作るよう設定する
add_index :relationships, [:follower_id, :followed_id], unique: true
ここでは指定した2つのカラムの組み合わせが一意になるよう設定している
→あるユーザーが同じユーザーを2回以上フォローするのを防ぐため
rails db:migrate
でテーブルを作成
能動的関係に対して1対多 (has_many) の関連付けを実装する
class User < ApplicationRecord has_many :active_relationships, class_name: "Relationship", foreign_key: "follower_id", dependent: :destroy end
:active_relationships
は仮の名前、メソッド名になる
class_name: "Relationship"
実態はRelationshipだよって明示してる。じゃないと存在しないactive_relationshipsテーブルを探しに行ってしまう。
foreign_key: "follower_id"
外部キーを指定。さもないとactive_relationships_idを探しに行ってしまう
dependent: :destroy
あるユーザーが削除されたら、そのユーザーの関連も消す。relationshipsテーブルのレコードを消す。
リレーションシップ/フォロワーに対してbelongs_toの関連付けを追加する
class Relationship < ApplicationRecord belongs_to :follower, class_name: "User" belongs_to :followed, class_name: "User" validates :follower_id, presence: true validates :followed_id, presence: true end
validates presence: true
で保存するとき空だとエラーでるようにする
ここまでで使えるようになったメソッド
メソッド | 用途 |
---|---|
active_relationship.follower | フォロワーを返します |
active_relationship.followed | フォローしているユーザーを返します |
user.active_relationships.create(followed_id: other_user.id) | userと紐付けて能動的関係を作成/登録する |
user.active_relationships.create!(followed_id: other_user.id) | userを紐付けて能動的関係を作成/登録する (失敗時にエラーを出力) |
user.active_relationships.build(followed_id: other_user.id) | userと紐付けた新しいRelationshipオブジェクトを返す |
followingの関連付け
user.followings
になるようfollowingsにする。:source
を使って
「following配列の元はfollowed idの集合である」ということを明示的にRailsに伝えます。
class User < ApplicationRecord has_many :active_relationships, class_name: "Relationship", foreign_key: "follower_id", dependent: :destroy has_many :followings, through: :active_relationships, source: :followed end
こんなことができるようになる 特定のユーザーがフォローしてるユーザーリストを配列のように使える
user.followings.include?(other_user) 居る? user.followings.find(other_user) 取得 user.followings << other_user 追加 user.followings.delete(other_user) 削除
followingsで取得した集合からフォロー・アンフォローのメソッドを作る
# ユーザーをフォローする def follow(other_user) active_relationships.create(followed_id: other_user.id) end # ユーザーをフォロー解除する def unfollow(other_user) active_relationships.find_by(followed_id: other_user.id).destroy end # 現在のユーザーがフォローしてたらtrueを返す def following?(other_user) followings.include?(other_user) end
受動的関係を使ってuser.followersを実装する
user.followers
メソッドを追加する。フォロワーの集合を取得する。user.followings
の逆
class User < ApplicationRecord has_many :active_relationships, class_name: "Relationship", foreign_key: "follower_id", dependent: :destroy has_many :passive_relationships, class_name: "Relationship", foreign_key: "followed_id", dependent: :destroy has_many :followings, through: :active_relationships, source: :followed has_many :followers, through: :passive_relationships, source: :follower end
この場合なら、has_many :followers
を単数形にして自動的に外部キーfollower_id
を探してくれるからsource
を省略しても動く。比較の為あえて書いてる。
ルーティングを設定する
config/routes.rb
resources :users do member do get :followings, :followers end end
これで/users/1/following
や /users/1/followers
を表してる
HTTPリクエスト | URL | アクション | 名前付きルート |
---|---|---|---|
GET | /users/1/followings | followings | followings_user_path(1) |
GET | /users/1/followers | followers | followers_user_path(1) |
resources :users do collection do get :tigers end end
collection
を使うとidを含まなくなり、この例では/users/tigers
のようになる
フォロワーの統計情報を表示するパーシャル
app/views/shared/_stats.html.erb
<% @user ||= current_user %> <div class="stats"> <a href="<%= following_user_path(@user) %>"> <strong id="following" class="stat"> <%= @user.following.count %> </strong> following </a> <a href="<%= followers_user_path(@user) %>"> <strong id="followers" class="stat"> <%= @user.followers.count %> </strong> followers </a> </div>
@ u s e r がnilであればcurrent_user
を代入してる
<%= render 'shared/stats' %>
レンダー
フォロー・フォロー解除のパーシャル
app/views/users/_follow_form.html.erb
<% unless current_user?(@user) %> <div id="follow_form"> <% if current_user.following?(@user) %> <%= render 'unfollow' %> <% else %> <%= render 'follow' %> <% end %> </div> <% end %>
ユーザーをフォローするフォーム
リレーションシップを作成
app/views/users/_follow.html.erb
<%= form_for(current_user.active_relationships.build) do |f| %> <div><%= hidden_field_tag :followed_id, @user.id %></div> <%= f.submit "Follow", class: "btn btn-primary" %> <% end %>
<%= hidden_field_tag :followed_id, @user.id %>
hidden_field_tagで
<input id="followed_id" name="followed_id" type="hidden" value="3" />
を生成している
隠しフィールドのinputタグを使うことで、ブラウザ上に表示させずに適切な情報を含めることができます。
ユーザーをフォロー解除するフォーム
リレーションシップを削除
app/views/users/_unfollow.html.erb
<%= form_for(current_user.active_relationships.find_by(followed_id: @user.id), html: { method: :delete }) do |f| %> <%= f.submit "Unfollow", class: "btn" %> <% end %>
<%= render 'follow_form' if logged_in? %>
適切な場所でレンダーする
followingアクションとfollowersアクション
ルーティングに従って2つのアクションを作る
renderで同じビューファイルを指定する
app/controllers/users_controller.rb
class UsersController < ApplicationController before_action :logged_in_user, only: [:index, :edit, :update, :destroy, :following, :followers] def following @title = "Following" @user = User.find(params[:id]) @users = @user.followings.paginate(page: params[:page]) render 'show_follow' end def followers @title = "Followers" @user = User.find(params[:id]) @users = @user.followers.paginate(page: params[:page]) render 'show_follow' end end
フォローしているユーザーとフォロワーの両方を表示するshow_followビュー
app/views/users/show_follow.html.erb
<% provide(:title, @title) %> <div class="row"> <aside class="col-md-4"> <section class="user_info"> <%= gravatar_for @user %> <h1><%= @user.name %></h1> <span><%= link_to "view my profile", @user %></span> <span><b>Microposts:</b> <%= @user.microposts.count %></span> </section> <section class="stats"> <%= render 'shared/stats' %> <% if @users.any? %> <div class="user_avatars"> <% @users.each do |user| %> <%= link_to gravatar_for(user, size: 30), user %> <% end %> </div> <% end %> </section> </aside> <div class="col-md-8"> <h3><%= @title %></h3> <% if @users.any? %> <ul class="users follow"> <%= render @users %> </ul> <%= will_paginate %> <% end %> </div> </div>
provideメソッドでパラメータを引き渡し
<% provide(:title, "Home") %>
yieldメソッドで受け取る
<title><%= yield(:title) %></title>
gravatar_for
gravatarっていうオンラインにプロフィールを置くサービスがあるらしい
userインスタンスを使ってgravatarから対応するプロフィール引っ張ってくるようにgravatar_forヘルパーメソッドを定義するっぽい。
gravatarで実際に登録とかしたら詳しくわかりそう。
フォロー・フォロー解除ボタンを動作させる リレーションシップの作成と削除なので、relationshipsコントローラが必要
[Follow] / [Unfollow] ボタンを動作させるためには、フォームから送信されたパラメータを使って、followed_idに対応するユーザーを見つけてくる必要があります。その後、見つけてきたユーザーに対して適切にfollow/unfollowメソッドを使います。
$ rails generate controller Relationships
Relationshipsコントローラ
app/controllers/relationships_controller.rb
class RelationshipsController < ApplicationController before_action :logged_in_user def create user = User.find(params[:followed_id]) current_user.follow(user) redirect_to user end def destroy user = Relationship.find(params[:id]).followed current_user.unfollow(user) redirect_to user end end
メモ
ルーティングのmember
https://railsguides.jp/routing.html#%E3%83%A1%E3%83%B3%E3%83%90%E3%83%BC%E3%83%AB%E3%83%BC%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0%E3%82%92%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8B
こう書いたら
get '/photos/123/preview', to: 'photos#preview'
ができるような感じ。
params[:id]
を渡す。
URLヘルパーも作られるpreview_photo_url
、preview_photo_path
resources :photos do member do get 'preview' end end
GETリクエストとそれに伴う'/photos/1/preview'を認識し、リクエストをPhotosコントローラのpreviewアクションにルーティングし、リソースid値をparams[:id]
に渡します。
同時に、preview_photo_url
ヘルパーとpreview_photo_path
ヘルパーも作成されます。
patch
、put
、post
、delete
必要であればその都度書く。
なんで関連付けするの?
https://railsguides.jp/association_basics.html
アソシエーション(関連付け)すると
class Author < ApplicationRecord has_many :books, dependent: :destroy end class Book < ApplicationRecord belongs_to :author end
本を1つ作る @book = Book.create(published_at: Time.now, author_id: @author.id) 作者を削除、書いた本も削除する @books = Book.where(author_id: @author.id) @books.each do |book| book.destroy end
これが、こうなる。シンプルになる。
本を1つ作る @book = @author.books.create(published_at: Time.now) 作者と書いた本を削除 @author.destroy
has_many :throughの関連付け
多対多の時に、中間テーブルを使う。その時に使う。次の例ではAppointmentが中間テーブル
class Physician < ApplicationRecord has_many :appointments has_many :patients, through: :appointments end class Appointment < ApplicationRecord belongs_to :physician belongs_to :patient end class Patient < ApplicationRecord has_many :appointments has_many :physicians, through: :appointments end
直接相手のモデルから情報取りに行こうとすると多対多になるから:throughで中間テーブルを経由して~って言ってる。
Railsチュートリアルのフォロー機能実装の場合はさらに自己参照だからややこしいことに・・・
https://railsguides.jp/association_basics.html#%E8%87%AA%E5%B7%B1%E7%B5%90%E5%90%88
自己結合のとこも参考になる。
双方向関連付け
a = Author.first b = a.books.first a.first_name == b.author.first_name # => true a.first_name = 'David' a.first_name == b.author.first_name # => true
Active Recordは関連付けの設定から、これら2つのモデルが双方向の関連を共有していることを自動的に認識します。以下に示すとおり、Active RecordはAuthorオブジェクトのコピーを1つだけ読み出し、アプリケーションをより効率的かつ一貫性のあるデータに仕上げます。
しかし、:through
, :foreign_key
を使った場合は自動的に認識されない
a = Author.first b = a.books.first a.first_name == b.writer.first_name # => true a.first_name = 'David' a.first_name == b.writer.first_name # => false
Active Recordは
:inverse_of
オプションを提供していて、これを使うと双方向の関連付けを明示的に宣言できます。
class Author < ApplicationRecord has_many :books, inverse_of: 'writer' end class Book < ApplicationRecord belongs_to :writer, class_name: 'Author', foreign_key: 'author_id' end
:foreign_key
Railsの慣例では、相手のモデルを指す外部キーを保持しているjoinテーブル上のカラム名については、そのモデル名にサフィックス_idを追加した関連付け名が使われることを前提とします。:foreign_keyオプションを使えば、外部キーの名前を直接指定できます。
:inverse_of
:inverse_ofオプションは、その関連付けの逆関連付けとなるhas_many関連付けまたはhas_one関連付けの名前を指定します。
class Author < ApplicationRecord has_many :books, inverse_of: :author end class Book < ApplicationRecord belongs_to :author, inverse_of: :books end