“初めての自動テスト”は様々な人に手にとって読んでほしいものだった

9月21日に発売された”初めての自動テスト ―Webシステムのための自動テスト基礎”を恵贈いただいたことと、少しレビューさせて頂きましたので合わせてこの書籍に関して書こうと思います。(以下、本書)

この本は元々、The Pragmatic Bookshelfでβ販売から開始されたThe Way Of The Web Testerが玉川さんによって翻訳されたものです。この書籍の著者は、アジャイルサムライを書かれたJonathan Rasmussonさん。

私はβ配信の頃にこの書籍を見つけ、過去、このBlogにおいても簡単な感想を書きました。その頃から少し後半が更新、少し内容が追加され、2017年6月29日に最新版が配布されました。本書はその最新版を翻訳したものですので、その内容は最新のThe Way Of The Web Testerと同等のものとなっています!

私は、玉川さんととある活動で知り合っていたこともあり、本書の翻訳レビューと主にはRubyコードに関わるところで相談させていただきました。また、過去にこの書籍の原書を読んで内容の素晴らしさを感じていたので、レビューの相談を頂いたさいも良い意味でとても驚きました。レビュー時から感じていたのですが、この翻訳版である本書の表現などの素晴らしさは玉川さんのご尽力のおかげです。とても良い仕上がりになっているかと思います。

本書に軽く触れる前に、私がこの書籍で好きなところを残しておきます。本書は、開発プロセスなどのテストに関わる周辺環境をなるべく剥がし、テストやそのコードに関わるところの足場に注力しているところです。一方で、ただ単にテストコードの話だけに止めるのではなく、そこに至るまでの話を チーム を中心にしているところが気に入っています。そのため、英語版、日本語版共に、これからテストに入門する人、経験の少ない人、経験の深い人各々に、それぞれの良さをつけてオススメしたいと思っています。

ここで少し話を脱線すると、本書に書かれているレガシーコードに対するUIテストの導入話や、テストピラミッドの話は、少し前にtry!Swiftにてお話させて頂きました内容と同じようなことも言っています。そのため、本書はWebと題しながらも、モバイルなどにも汎用的に使える考え方も多いことを感じるでしょう。

では、少し本書に触れます。

チームの人に

第1章、第8章は概念、実際にテストを導入するときに気にしないといけないところを中心に書いています。そのため、広くチーム全員にオススメします。この箇所で共通認識を持っていると、導入するテストの全体像に対する共通認識を説得する手間が省けるとおもます。読書会みたいな感じで話し合うのも良いかもしれません。また、ここではプロダクトに対するテストの全体像、どんなテストを、どのくらいの量、自動化すると有用かということを知るもとができます。

コード書く経験があまりない人に/手動テストが主な人に

8章までは基礎的なことが書かれているため、そこでテストコードの実装含め、基礎を学ぶことができます。実際にコード書きながら様々なユニットテストを学んだり、Webアプリの仕組みを大まかに学ぶことがでるためです。ここを学ぶと、発展的な内容を学ぶ土台となる知識が得られ、プログラミングが関わるような勉強会でもある程度話が想像できるようになると思います。

9章以降ではもう少しちゃんとプログラミングに触れたり、より良いテストコードの書き方、テストファーストの考え方まで学ぶことができます。本書にも書いてますが、本書をざっと学び、コードを書きながら経験を積んだ後には、よりテストコードを書き、よりコードを書く経験を増やし、他の書籍などを読みながら自分の力で自動テスト関係やその周辺環境の経験を増やしていけるでしょう。

本書を読み終えたら

プログラミング言語でいうとここではRubyを題材にしていますが、モバイルに足を踏み入れるとJavaやKotlin、Objective-CやSwiftに触れる必要が出てくるでしょう。また、Webでも他の言語を学ぶことができます。言語におけるテストコードの文化や書きやすさの違い、プラットフォームによるテストし易さの違いを学びながら、より発展的なエンジニアとしての道を歩むことができるでしょう。

よりテスト技術に関して学びたい場合は、テスト技法関連の書籍を追ったり、GitHubなど含めてモックライブラリなどのライブラリを追うと良いでしょう。様々な、それぞれ使用感の異なる多様なライブラリに出会い、それぞれの良し悪しを学んだりできるかと思います。

また、ここの学んだことをベースに、アジャイルテスターのような方面に足を踏み入れることも挑戦的で面白いかと思います。開発プロセスなどが絡む方面に進むこともまた面白いかもしれません。

いずれにせよ、本書は様々な経験をする足場を学ぶことができるので、ぜひ手を取ってみていただければと思います。

Advertisements

[Elm]getting start Elm language

Elm is a functional language that compiles to JavaScript

GitHub : https://github.com/elm-lang

知ってはいたのですが触っていなかったElm。少しきっかけがあったので触ってみました。
※Elmについて、といった内容はここでは触れません。

この理由としては、チームメンバの1人がSwiftでとある機能を実装している時にこのElm Architectureから構成をインスパイアされたといっていたためです。といっても、Elm Architecture付近をチュートリアルを元に学んでみたというくらい。なので記法を学ぶというよりは、どんな問題を解決しようとどういう設計を行ったか、です。(そういえば、このElm->JSのコンパイラはHaskell製)

試したElmは0.18.0

tutorial(guide): https://guide.elm-lang.org/

tutorialをいくつか実際に動かしたGitHub repository: https://github.com/KazuCocoa/my_first_elm

Elm、実行環境も elm-repl コマンドでターミナル上から簡単に動作みることできるし、 elm-reactor コマンド実行するとローカルホストにブラウザでアクセスするとすぐに動作みることができるので触ってみる障壁がとても低くて感動しました。ドキュメンテーションとか、コミュニティパッケージ群も揃っていました。テストツールとかも、パッケージとしていくつも既に存在しているみたいです。

Elixirをもともと触っていると感じたのですが、なかなかElixirと似通ったものがありました。類似言語に影響を受けているっぽいので文法的なところもなのですが、 One crucial detail here is that commands and subscriptions are data と書いていたり、 Elm treats errors as data とあるように、データの流れを基軸として表現しようとしているところです。

では、かいつまんで。

Architecture

Elmの実装設計パターンは画面の操作を以下のように3つに分割してデータを記述するところ、データを更新するところ、それをViewに反映するところ、で分けるところです。これにより、基本的なボタンをタップするとか、そういうことに対してデータを受け取り、更新し、Viewに反映するという一定の操作を決まった定型文によって区切りながら実装することができるようになっています。

  • Model — the state of your application
  • Update — a way to update your state
  • View — a way to view your state as HTML

これに加え、例えばHTTP通信などの非同期処理などの命令を扱うためにも以下のように2種類の定義も追加されました。( https://guide.elm-lang.org/architecture/effects/ )

  • Commands — A Cmd lets you do stuff: generate a random number, send an HTTP request, etc.
  • Subscriptions — A Sub lets you register that you are interested in something: tell me about location changes, listen for web socket messages, etc.

Elmはこのeffectsの箇所でも以下のように書いている通り、この commandssubscriptions もデータを記述しElmフレームワークに渡すためだけのものとして扱うようです。そこらへんから結果を受け取ってViewに反映させるまでの受け渡しはElm側がみていると。

Aside: One crucial detail here is that commands and subscriptions are data. When you create a command, you do not actually do it. Same with commands in real life. Let’s try it. Eat an entire watermelon in one bite! Did you do it? No! You kept reading before you even thought about buying a tiny watermelon.
Point is, commands and subscriptions are data. You hand them to Elm to actually run them, giving Elm a chance to log all of this information. In the end, effects-as-data means Elm can:
– Have a general purpose time-travel debugger.
– Keep the “same input, same output” guarantee for all Elm functions.
– Avoid setup/teardown phases when testing update logic.
– Cache and batch effects, minimizing HTTP connections or other resources.
So without going too crazy on details, pretty much all the nice guarantees and tools you have in Elm come from the choice to treat effects as data! I think this will make more sense as you get deeper into Elm.
> from https://guide.elm-lang.org/architecture/effects/

あと、エラーハンドリングのところも昨今のnullやexceptionの扱いに関して言及していてよかったです。Erlang/Elixirを触っていると結果はだいたい {:ok, xxx}{:error, xxx} として処理を分けることがほとんどなのですが、そのような感じですね。

実装され、提供されている機能は以下。

  • Maybe
  • Results
  • Task

Null

I call it my billion-dollar mistake. It was the invention of the null reference in 1965. At that time, I was designing the first comprehensive type system for references in an object oriented language (ALGOL W). My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn’t resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years.
> 本文より

Exceptions

Joel Spolsky outlined the issues with exceptions pretty nicely in the year 2003. Essentially, code that looks fine may actually crash at runtime. Surprise!

以下なんかをみていると特に、Elixirでいう case ... do ... end の形を思い出します。

締め

1日程度触った感じですが、Elm、なかなかElixirやSwift書いている人にすると比較的学びやすいJS実装な気がします。今後使い続けるかは別にして、関数型言語の領域を学ぶというところでは情報も多すぎず程よいかもしれません。

[Elixir]compile timeに決定されるモジュールの定数

Elixirでは以下のように @neko と定義することで、このモジュール内で共通して使える要素を定義できます。最近使い方を誤ってしまったのですが、この値はコンパイル時に決定されるので、それ以降に読まれる値を設定することはできません。

defmodule Sample do
  @neko "value"
end

In other words, the value is read at compilation time and not at runtime. As we are going to see, this makes attributes useful to be used as storage during module compilation.

http://elixir-lang.org/getting-started/module-attributes.html

例えば、

defmodule Sample do
  @neko Application.get_env :sample, :value, "default"
end

というような用途では、必ず default が代入されます。

つい忘れていてつまづいたので、メモ…

[Elixir]Release http_proxy support record/play request

I released http_proxy 0.3.0 which support play/record http request.

Now, the library support multiple port proxy and each proxies support play/record request.

Hex: https://hex.pm/packages/http_proxy
Docs: http://hexdocs.pm/http_proxy/0.3.0/extra-api-reference.html
GitHub: https://github.com/KazuCocoa/http_proxy

『7つの言語 7つの世界』を読んだ

7つの言語 7つの世界』を読みました。電子書籍は、このeBook StoreのWebサイトから購入しました。ちょうどeBook Storeのリニューアルキャンペーンで安く購入できるようになったので、これを機に読んでみることにしました。

取り上げられた言語が開発された背景、概念、目指すものなどがうまいことまとめられています。また、それらが解決したいとしていた問題など含めて。

私は言語仕様自体ではなく、それらが解決したいとしていた現実問題やその成長の歴史を学び、現実の問題にフィードバックを与えることに興味があります。そういう意味で、私がこの本に興味を持ったのはちょうどよかったです。

取り上げられている言語は以下。これらに絞った理由などはこの本書に書かれているのでここでは除きます。

  1. Ruby
  2. Io
  3. Prolog
  4. Scala
  5. Erlang
  6. Clojure
  7. Haskell

私はRuby/Scala/Erlangはある程度触ったことがありました。Ioは唯一、初めて見聞きしたものでした。他は聞いたことはあるけれどまだ踏み込んでいないものです。それらの概要や基本的な書き方、特徴的な箇所をざっと知り、それらの成長の課程を学ぶことは読み物としても興味深いものでした。

読んでいて、例えばElixirの言語設計にClojureに影響されたと書かれている箇所が多分にあるのですが、そこの影響された箇所がわかったりしてなかなかに面白かったです。Haskellのモナドなんかは、写像とか、そういう言葉は理解できるけれどそれがプログラミング言語としてどう現実解に落とされているかぱっときてませんでした。そこへの取っ掛かりも得ることができました。

こういうプログラミング言語などの発展は、やはり解決したい問題とこれまでの蓄積があるのですね。

あと、この本で楽しかったのが各言語がなんらかの物語に照らし合わされていたことです。例えばErlangは映画・マトリックスの世界で語られていました。Haskellはスタートレックのスポックなど。

[Elixir]implement binary search with Elixir

ElixirでBinary Searchを実装してみた。メモ。

[Elixir]1worker、1portでリクエストを待ってHTTPのリクエストをProxyする

HerokuがErlang製のHTTP Proxyを公開しましたね。少し中身見てみたのですが、彼らもForkしたCowboyを使ってProxyを構築しているっぽい。他にも軽く読んでは見たのですが、Erlangも多少読めるようになっててびっくり。

https://github.com/heroku/vegur

話は少し変わって、[Elixir]Elixirで簡単なHTTP Proxyを書いているときに出会ったエラーのメモで、Supervisorのworkerごとに異なるportを待ち受けてそれぞれが独立したproxyとして動作する機構を書いてたのですが、PIDの衝突の発生で思った感じでできてませんでした。

でも、考えるほどにやっぱりできるはずだよなーと思いもう少しやってみました。それと、先ほどのVegurでもやっぱり異なるPortで待ち受ける処理が書いてあって、やっぱり実装間違ってるなと確信。

もう一度考え直してみると、今回は考えた通りに書いていったら期待通り動作することができました。
結局は、 Plug.Adapters.Cowboy.http に対して与えている ref の与え方が間違っていた、という情けないミスでした…

リポジトリ: https://github.com/KazuCocoa/http_proxy

前回の誤り

def start_link(proxy) do
  Plug.Adapters.Cowboy.http __MODULE__, [ref: proxy[:name]], port: proxy[:port].port
end

今回

def start_link(proxy) do
  Plug.Adapters.Cowboy.http(__MODULE__, [], [port: proxy.port, ref: String.to_atom(module_name)])
end

これで、例えば以下のような実装を書いたときに、Supervisorで監視される各々のWorkerが異なるProcessとPortでリクエストを待つことができるようになります。 HttpProxy.Handle のモジュールに、先ほどのCowboyの起動が実装されていることを想定しています。

  def init(:ok) do
    import Supervisor.Spec

    [%{port: 4000, ...}, %{port: 4001, ...}]
    |> Enum.reduce([], fn proxy, acc ->
      module_name = "HttpProxy.Handle#{proxy.port}"
      [worker(HttpProxy.Handle, [[proxy, module_name]], [id: String.to_atom(module_name)]) | acc]
    end)
    |> supervise(strategy: :one_for_one)

  end

修正時のコミット(ファイルの置き換えあり): https://github.com/KazuCocoa/http_proxy/commit/8b5368f15a2e149ac7069a33379e4c190cf93374


Elixir/Erlangさわりはじめて、大学の頃もでしたが、やっぱり私は分散系に対して技術的な興味を持っているのだなーと感じました。

[Elixir]ex_topで各PIDの動作をみる

Elixir/Erlangのprocessに対してtopコマンドを実行できるライブラリ

https://github.com/utkarshkukreti/ex_top

[Elixir]Elixirで簡単なHTTP Proxyを書いているときに出会ったエラーのメモ

追記 2015/11/08

[Elixir]1worker、1portでリクエストを待ってHTTPのリクエストをProxyする で解消済


最近、簡単なHTTP Proxyを書いてみています。Elixir/Erlangの多プロセスで動作する点を利用して、軽量なproxyとして動作できるのかなー?というところがあってです。

https://github.com/KazuCocoa/http_proxy

以下のような感じでportを指定したら、そのportに対してどんなパスでアクセスしたかで接続先を制御できる感じにしています。

use Mix.Config

config :http_proxy,
  proxy: %{port: 4000,
           default_to: "http://google.com",
           path: [
               %{from: "", to: "http://yahoo.com"},
               %{from: "neko", to: "http://yahoo.co.jp"}
             ]
           }

PlugCowboy を結局は使っています。Supervisorのworkerとしてプロセスは起動するようにもしています。

この動作確認の中で、ElixirのSupervisorで複数のPlugを持つ同一モジュールを動かそうとしたらPIDの競合でエラーがでたのでメモ。少し調べてみると、それはPlugが Plug.Adapters.Cowboy.httpPlug.Adapters.Cowboy.https をSupervisorで起動するときに :name__MODULE__ を指定しているのが原因な気がしています。

というのも、例えばSupervisorで呼ばれたときにまず起動するここらへんで使われる、start_link で最初に呼ばれるところで ref: を与えたり、

  def start_link(proxy) do
    {:ok, pid} = Plug.Adapters.Cowboy.http __MODULE__, [ref: proxy[:name]], port: proxy[:port].port

    IO.inspect pid
    {:ok, pid}
    # :timer.sleep(:infinity)
  end

workerで与える :id を変えても変化なかったためです。ここな感じ。

  def init(:ok) do
    import Supervisor.Spec

   children = [
     worker(HttpProxy, [[port: 4000, name: String.to_atom("HttpProxy1")]], [id: String.to_atom("HttpProxy1")]),
     worker(HttpProxy, [[port: 4001, name: String.to_atom("HttpProxy2")]], [id: String.to_atom("HttpProxy2")])
   ]

    supervise children, strategy: :one_for_one
  end

[Elixir]GenServerのcallとhandle_callにおける:nameによる指定

GenServer.start_link __MODULE__, default, [name: __MODULE__]name を指定することの必要性に関してメモ。

以下の通り、Sample.neko を読んだ時、 __MODULE__ にメッセージが送られてGenServerのコールバックであるhandle_call にメッセージが送られる。そのパターンマッチで処理される handle_call が決定、実際にプロセスで処理される。という一連の処理を作るために、 start_link では名前をちゃんと与えることが必要。そうでなければ、process idを直接指定しなくてはいけない。(それはあまり現実的ではない..)

defmodule Sample do
  use GenServer

  def start_link(default) do
    GenServer.start_link __MODULE__, default, [name: __MODULE__]
  end

  def neko(token \\ []) do
    GenServer.call __MODULE__, {:neko}
  end

  # sever
  def handle_call({:neko}, _from, state) do
    case token do
      :token ->
        {:reply, client(:token), state}
      _ ->
        {:reply, client, state}
    end
  end
end

関連した修正はこちら

https://github.com/KazuCocoa/my_bot_ex/commit/b9be93de02e47b97a2a2e93dcbb46104ddb47004