matobaの備忘録

育児しながら働くあるエンジニアの記録

Rustで標準入力を受け取って、標準出力に出してみただけの話

Rustで標準入力を受け取って、標準出力に出してみただけの記録を書きます。

以下の本を読んでいたら、こんなサンプルがありました。

数当てゲームをプログラムする - The Rust Programming Language 日本語版

use std::io;


fn main() {
    println!("Guess the number.");

    println!("Please input your guess.");

    let mut guess = String::new();

    io::stdin().read_line(&mut guess).expect("Failed to read line.");

    println!("You guess: {}", guess);
}

このページは、解説を読みながら、自分なりの理解をメモしていきます。

ライブラリを読み込む

以下の行で、標準ライブラリstdの中に存在するioライブラリを読み込む。

use std::io;

関数を定義する

関数は以下で定義できる。

fn main() {
}

mainはエントリーポイントでもある。

fnで関数を表す。上記は引数や返り値を持たないが、持つケースは追々学べるハズ。

こんな風に構造化できる。

fn hello() {
    println!("hello");
}

fn main() {
    hello();
}

変数を宣言する

以下のようにして、変数を宣言できる。

let foo = 5;

ただし、このfooはimmutableになる。つまり、変更することができない。

以下のような関数があってコンパイルするとエラーが出る。

fn define_foo() {
    let foo = 5;

    foo = foo + 1;
    println!("foo: {}", foo);
}

エラー内容

 --> src/main.rs:6:5
  |
4 |     let foo = 5;
  |         ---
  |         |
  |         first assignment to `foo`
  |         help: make this binding mutable: `mut foo`
5 |
6 |     foo = foo + 1;
  |     ^^^^^^^^^^^^^ cannot assign twice to immutable variable

可変の変数を宣言したい場合は、mutをつける。

fn define_foo() {
    let mut foo = 5;

    foo = foo + 1;
    println!("foo: {}", foo);
}

これでコンパイルが通る。Rustでは変数は標準が不変らしい。

変数が標準で不変になっていると何が嬉しいのかは今のところよくわかっていない。

変数の型を束縛する

以下の行は、guessという変数にString型のオブジェクトのnew関数を呼び出した結果で束縛している。

let mut guess = String::new();

現時点では、「束縛する」という概念が何なのかはよくわかっていない。 とりあえず、その型しかいれられないようになるのかな、くらいのイメージで進む。

なお、Stringは標準ライブラリによって提供される文字列の型らしい。 newといういわゆるスタティックメソッドを持っている。Rustでは「関連関数」と呼ぶらしい。

読み込んだライブラリの関数を呼び出す

use std::io; で読み込んだioライブラリのstdin関数を呼び出す場合、以下のようになる。

io::stdin()

なお、 use std::io で事前に読み込んでいない場合、 次のように呼び出せるらしい。

std::io::stdin()

std::io::stdin() の返り値は std::io::Stdin というオブジェクトらしい。

オブジェクトのメソッドを呼び出す。

以下のように書くと、返ってきた std::io::Stdin に対してread_lineメソッドを呼び出せるらしい。

io::stdin().read_line(&mut guess)

&mut guess は変数として参照渡ししている。らしい。

guessって変数として定義したんじゃなかったっけ?とか思うけど、メソッドや関数に参照渡しして、書き換える時は、 mut が必要なのかな。 & が参照渡しを意味している様子。

今のところよくわかってないけど、関数とかメソッド呼び出しを学ぶときにもう少し詳しく知れるのだろう。

メソッドの処理結果を解釈する

io::stdin().read_line(&mut guess) を実行すると Result 型というものが返ってくるらしい。

Result側は、OkかErrらしい。

Rustでは、エラーが発生する可能性がある行で、エラーの際の処理を書いていないとコンパイル時に警告が発生するらしい。

io::stdin().read_line(&mut guess)
warning: unused `std::result::Result` that must be used
  --> src/main.rs:19:5
   |
19 |     io::stdin().read_line(&mut guess);
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: `#[warn(unused_must_use)]` on by default
   = note: this `Result` may be an `Err` variant, which should be handled

エラーハンドリングするの忘れなくて良さげ。

io::stdin().read_line(&mut guess)
    .expect("Failed to read line.");

ここでは、expectを書いて、わざとクラッシュさせているらしい。そのほかのハンドリングは追々学ぶ。

標準に入力に変数を埋め込む

printデバッグするために、変数を標準出力に出したいことはある。

そのときに使えそうな例。

println!("You guess: {}", guess);

説明は省略。

所感

とりあえず、標準入力を受け取って標準出力に出すサンプルを見つつ、勉強したことを記録した。

今のところ「へー。そうなんだー」という感じ。

この記事はわざわざ公開する必要もない内容を書いている。

Notionとか非公開のところに書けばいいと言う話もあるかもしれないけど、別に隠す話でもないのと、ブログなどを介して、「なんかやってる感」を出していきたかったり、自分の中で非公開状態のところにメモするより公開状態のところにメモする方が記憶に残るので、ブログに書いてみました。

まあ、気が向いたらRustについて学び進めていきます。

Rustをインストールして、Hello Worldしただけの話

Rustを初めてみた記録を書きます。

参考資料

基本は以下のURLに従います。

The Rust Programming Language 日本語版 - The Rust Programming Language 日本語版

Rustのインストール

rustupはRustをインストール・更新するツールです。まずは、rustupをインストールします。 rustupをインストールすると、Rustに関するいろいろなツールをも一緒にインストールされます。

とりあえず、以下を実行します。macOS 10.15.7を使ってます。fishです。

$ curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh

途中でインストール設定を聞かれたので、僕は、デフォルトでインストールしました。

1) Proceed with installation (default)
2) Customize installation
3) Cancel installation
>1

あと、上記のドキュメントにはありませんでしたが、rustupのインストール後、以下のようなメッセージが出ます。

To get started you need Cargo's bin directory ($HOME/.cargo/bin) in your PATH
environment variable. Next time you log in this will be done
automatically.

「コマンドがインストールされたけど、パスは通ってないので、自分で通せ」という話ですかね。

10年くらい前の自分なら「パスって何だろう?どうやって通したらいいんだろう?」と思いながら、詰まったんだろうなあ。と思いながら、以下でコマンドがインストールされていることを確認しました。

> which rustup
[1]> ls ~/.cargo/bin
cargo*         cargo-fmt*     clippy-driver* rust-gdb*      rustc*         rustfmt*
cargo-clippy*  cargo-miri*    rls*           rust-lldb*     rustdoc*       rustup*

パスは通ってないものの、インストールはされているようです。

パスを通します。fishを使ってるので、以下のように書きます。(実際は他にもパスを書いてますが、省略)

~/.config/fish/config.fish

set PATH ~/.cargo/bin $PATH

そのあと、fishにログインし直して、パスが通っていることを確認します。

> which rustup
/Users/mtb/.cargo/bin/rustup

はい。OK。

Hello Worldしてみる

こんなコードを書き、hello.rs で保存します。拡張子は、.rsのようです。

fn main(){
    println!("Hello World!!");
}

以下のコマンドでコンパイルします。

rustc hello.rs

コンパイルしたら、 hello という実行ファイルができているので、実行すると標準出力に出ます。

> ./hello
Hello World!!

とりあえずここまでは簡単。

脱線:インストールされたツールを確認する

インストールしてHello Worldまで来たので、インストールされたツールが何なのかも確認しておきます。

と言っても、軽くhelpを読んだりリポジトリをサッと見るだけ。

  • cargo: Rust's package manager(Rustのパッケージマネージャー)
  • cargo-fmt: This utility formats all bin and lib files of the current crate using rustfmt.(rustfmtを使ってbinとlibをフォーマットするユーティリティ)
  • clippy-driver: Checks a package to catch common mistakes and improve your Rust code.(Rustコードのパッケージをチェックし、よくあるミスを発見して改善するツール)
  • rustc: (Rustのコンパイラ)
  • rust-gdb: (おそらくRustのデバッガ)
  • rustfmt: Format Rust code(Rustのフォーマッター)
  • cargo-clippy: Checks a package to catch common mistakes and improve your Rust code.(Rustコードのパッケージをチェックし、よくあるミスを発見して改善するツール)
  • cargo-miri: ???? (GitHubを見ると、Rustの実験的なインタープリタ。)
  • rls: Rust Language Server (IDEとの連携用)
  • rust-lldb: LLDB(コンパイラ基盤?)
  • rustup: The Rust toolchain installer(Rustのツールインストーラ)
  • rustdoc: Rustのドキュメント

公式のフォーマッターや静的解析ツール、Language Server、と最初から色々入ってるんだなあ、という印象を受けました。

とりあえず、cargo-fmtとrustfmt、cargo-clippyとclippy-driverの違いがよくわからないんですが、使っているととりあえずおいおいわかるんですかね。

とりあえず、終わり

これだけで、おわりかよっ!!って感じなんですが、今日は時間的にHello Worldと関連ツール調べただけで終わってしまいました。

次はもう少し、別のこともやってみたいところ。

また、気が向いたら、調べつつ、書きます。

ではでは。

バージョン管理システムの違いや仕組みについて調べていた話

数年前の過去の自分のブログ記事を整理していて、説明したい気持ちになったことがありました。*1

というわけでニーズがあるのか分かりませんが、今の時点での知識で説明を書きます。間違えてたり、変な話だったらすいません。

それは、バージョン管理システムの違いや仕組みの話です。

過去の自分が気になっていたこと

過去の自分はこんなことをしていました。

  • バージョン管理システムの違いが気になって調べていた
  • バージョン管理システム間で考え方の違いに戸惑っていた
  • 制作中の音楽のバージョン管理をしたくてモゴモゴしていた

今回は同じようなことを調べているかもしれない人の役に立てば良いなと思います。

ちなみに、ここに書いてある話は、コードだけバージョン管理できたらハッピーになれる人には関係のない話です。コードだけバージョン管理したい人は、GitとGitHubを使えば幸せになれます。

最後に、僕がなぜ、上記のようなことを調べた背景を書いてるので、気になった方は読んでもらえるとありがたいです。

まず、バージョン管理システムについて

とりあえず、こんなバージョン管理システムの話が含まれています。

  • Subversion
  • Mercurial
  • Git
  • 各種アプリ(エディタやDAW)に付属してるバージョン管理システム

僕が使ったことがあるバージョン管理システムの話を中心に広げます。

そもそもの話なのですが、バージョン管理システムで重要なのは、「バージョンとは何か」「バージョンをどうやって管理するか」です。

読者の方は、ソフトウェアエンジニアの方が多いと思うので、ソフトウェアのバージョン管理の話から考えます。

どうやってソフトウェアを管理するか

ソフトウェアのバージョン管理でいうと、一つのバージョンには、コードが記述された複数のファイルの状態とディレクトリ構造が含まれています。

で、どうやってバージョンを管理するか、の話なのですが、例えば、Mercurialはバージョンを直前のバージョンとの差分で管理しています。言い換えれば、データベースには直前のバージョンと直後のバージョンの差分が保存されています。Subversionもこの形式になっています。

各ファイルをdiffしてその差分を記録しているのです。

一方でGitはバージョンをファイルごと管理しています。 変更があったファイルをそのまま保存するのです。差分が一部だったとしてもファイルをそのまま保存します。ちょっとでも差分があれば、それは新しいファイルとして保存していて、差分がどれだけあるか、というのは保存していません。

この話の裏が欲しい人は、GitProのこの辺(Git - Gitの基本)を参照してください。

なぜ、Gitはファイルごと管理するのか

これがどう嬉しいかというと、Gitでは過去のバージョンにHEADを変えたときに、そのリビジョンにサクッと移動できるのです。Linuxでcdコマンドを実行した時と同じような体感で、リビジョンを変更できます。

直前との差分でバージョンを管理していると過去のバージョンを参照しようとしたときにも差分を辿っていかないといけません。複数のブランチで開発していたり、過去の履歴になればなるほど、過去バージョンの参照に時間がかかります。ただし、トータルで見たときのリポジトリの容量は差分で管理した方が少なくなります。必要なリポジトリの容量は、システムの費用に直結します。

これを別の言い方にすれば、過去のバージョンの仕様をコードやコミットログから把握しない前提を作れば、差分管理のバージョン管理を採用する方がトータルコストが下がる、ということです。逆に、差分管理のバージョン管理(SubversionやMercurial)を採用している場合、コードから仕様を把握するためのハードルがGitを使っている時と比べて上がっています。

GitはLinuxカーネルの開発者であるリーナストーバルス氏が、Linuxカーネルを開発するために作ったものです。Gitの略史というものがあるので、裏としてはこちらを参照してください。 see Git - Git略史

Gitは開発者がスムーズに特定のリビジョンを参照できるように作られた。ということを考えたら、どうしてそういう違いが生まれているのかを理解しやすいように思います。

どう使い分けるのですか?

こういう話をしていると、「では、若者(というか、数年前の僕)はSubversionやMercurialはどういうタイミングで使うといいのですか?」とか考えたくなっていました。

僕は今のところ、「とりあえず、Gitを使うようにしてGitを使ったときに発生する問題は、別の方法で対策する」と言うのが時代の流れのように思ってます。

とはいえ、気になる人は気になると思うので、今の僕が考えていることを説明してみます。

Subversionについて

あくまで予想の範疇ですが、Subversionが登場した時代(2000年ごろ)は、「今よりも業界の規模や予算が小さくて、費用を絞らざるを得なかった」とか「エンジニア一人当たりの生産性を上げるより、エンジニアの数を増やして、トータルの生産性を上げようとしていた」と言うのもあるのかもなあと、推察しています。

それから、その前段に「商用バージョン管理システムしかなくて、とりあえずオープンなバージョン管理システムが欲しい」みたいな話があったのかもしれないです。

ちなみに、過去の話がどうしても気になる人は、次のあたりの本を読むと良いかもです。

今は、「エンジニアの数を増やしても、トータルの生産性の上昇は効率が悪いから、できるだけ一人当たりのパフォーマンスをあげたい」とか、「ITがビジネスの中心になっているので、エンジニアの数を一人でも増やして、スピードアップしたい。エンジニアが高給でも雇いたい。開発マシンなんて安い」と言う時代なので、考えなくて良いと思います。

Mercurialについて

あと、Mercurialの歴史については、僕もWikipedia情報ですが、こちらもそもそもがLinuxカーネルの開発者であるMatt Mackall氏が開発を進めていたもので、「ファイルそのものを管理するのではなく、差分を管理すべき」と言うのがコアの主張だったようです。

see: Mercurial - Wikipedia

GitもMercurialも2005年に登場したものです。

これも、あくまで予想の範疇ですが、当時は、今よりもネットワークの速度が遅かったり、ストレージ単価が高かったりしました。あと、GitHubもなくて、オープンソース活動が活発と言う状況でもなかったのだろうなあ、と言うことを省みると「Gitのようなファイル単位で管理する仕組みを導入すると、開発を行うために必要なハードウェアが高価になる。そうすると、オープンソース活動への参加障壁が上がってしまう。Linuxのようなオープンに開発を進めるソフトウェアは、率先して、開発への参加障壁も下げるべきである。だから差分でファイルを管理すべきだ」と言う考えがあったんじゃないかなあ、などと思ったりしました。

ですので、もし、現場でMercurialを使おうとしてたり、使っている職場があるなら、そのベースには「たくさんの人にソフトウェア開発に参加して欲しい」とか「ソフトウェア開発をするの準備費用を下げて、できるだけ多くの人に給料を出したい」みたいな気持ちがある可能性もなきにしもあらずかなあ、と思います。

とはいえ、今はネットワーク速度も上がって、ストレージ単価も下がっていていますし、GitHubもありますので、そう言う話はおいといて、Gitを選ぶと言うことで良いように思います。

ついでのお話

あと、ついでに伝えておくと、少ないないとは思いますが、現在でもMercurialやSubversionを使っているプロジェクトはあるんじゃないかなあ、と思います。

そう言うプロジェクトに遭遇した際に「えっ、Gitを使ってないとかどれだけ時代遅れw」みたいな煽りを入れるのはやめましょう。

MercurialにしてもSubversionにしても、なんらかの問題を解決してきた素晴らしいソフトウェアですし、それらの技術を選定した人にも何らかの考えがあって選んでいるので、敬意を払うのをオススメします。

あと、そもそもソフトウェアが微妙なら途中で捨てられるので、長く続いているプロジェクトはそれだけで価値を生み出しているとも言えます。

と言うわけで、そういう現場に遭遇したら、先人に敬意を払いつつ「おっ、今、流行のDXに最適な題材があるじゃん」と思って、Gitへの移行を頑張るのをお勧めします。

なお、及川卓也氏のソフトウェア・ファーストによるとDXは、「自社プロダクトの成長に関わるコア技術を自分たちが主導権を持って企画・開発できるようにすること」です。Gitは管理より企画や開発のスピードに重きが置かれたツールですので、DXと言う言葉を使えば、Gitに移行しやすいかもしれません。(他人事ですが)

もし、それが嫌でさっさと最新技術だけを使いたいのであれば、速やかにスタートアップに転職するのがお勧めです。ただ、そちらはそちらで最新技術を使い続けるフィールドなので、どちらが幸せかはわからないのですが。

アプリのバージョン管理について

さて、上記の話を踏まえた上で、アプリでのバージョン管理の話をします。

アプリのバージョン管理を考える場合は、何をファイルそのもので管理して、何を構造データとしてデータベースに保存するかを考えることが必要だと思います。

当たり前ですが、次のようなデータは、データベースに保存すると、扱いやすいと思います。

  • プロジェクト名
  • プロジェクトの設定
  • 起動バージョン
  • 導入されているプラグインの種類
  • プラグインの設定情報
  • プロジェクトの中に含まれるファイルのパス一覧

言わずもがなですが、データベースに保存しておくことで、検索がしやすくなりますし、一括更新もできるようになるからです。

あとは、これらの管理は、差分管理ではなくて、要素単位のスナップショットをデータベースに格納していくと検索も復旧も差分抽出もしやすくなるんじゃないかなと思います。diffの場合は比較したいリビジョンを両方持ってきて、diffをとれば良いので、シンプルですし、復旧もある地点以前の最新を持ってくればいいので。

PythonのDjangoのAdmin画面には、変更履歴管理機能がついていますが、参考になりそうな気がします。

それから次のようなデータは、データベースに格納するのはなくて、安価なストレージに配置するのが良さそうです。*2

  • 画像
  • 映像
  • その他ログや時系列データ

当然ですが、一つ一つの情報が大きい上に、人間の視点でちょっと修正するとファイル全体に修正がかかります。一方でスナップショットをとらないと、いざ、特定のバージョンに回帰したいとなったときに、時間がかかりすぎます。そもそも、これらの情報のバージョン管理では、差分が求められることはそうそうないように思います。データだけを比較してdiffをとることは難しいので、基本的に二つのバージョンを出して、人間が見比べる状況になります。

ですので、基本は、常に新しいファイルをストレージに保存することにして、データベースで参照先を管理するのが良いように思います。また、上記のようなメディアデータの保存は、少々重くてUX的によろしくないので、バックグラウンドで常に最新を保存し続けて、ユーザーが保存ボタンを押したら、DBの参照先だけを変えている様子のアプリも散見します。

なお、常に新しいファイルをストレージに追加し続けるパターンだと、ストレージの容量が膨張し続けて辛くなります。それを抑止するための仕組みはいくつかあって、パッと思いつく限り、次のパターンがあります。

  • 過去のリビジョン数に制限をかける(10個しか保持しない)
  • 参照可能なリビジョンの期間に制限をかける(1年分しか見せない)
  • リビジョンを何らかの条件で圧縮する(翌日になると、前日のファイルは一つだけにする。指定した区間のリビジョンをまとめさせる)

ファイルのバージョン管理は、いわばバックアップなので、バックアップをどう言う単位で持っておくか、と言う話と同じ話になります。ついでに言うと、このバージョン管理は、課金ポイントになりやすいように思います。

バージョン管理は、データの保持の仕方によって、使い勝手がかなり変わると思いますので、データをどうもつか、というのが結構重要なポイントだと思います。

そもそも、僕がやりたかったこと

はい。とりあえず今、思い出し分は書いたので、ここからはおまけの僕の話です。

僕は、バージョン管理について、いろいろ気になって調べていたのですが、その背景には「DAW(デジタルオーディオワークステーション)で音楽を作っている時のプロジェクトをスムーズにバージョン管理する仕組みが欲しい」と言う気持ちがありました。

学生時代の私は、DAWを使って音楽を制作していたんですよね。その当時で、50トラック以上のwavファイルをDAWに展開して、制作を進めていました。

waveファイルは、自身が演奏して収録したものから、打ち込みしたmidiデータをレンダリングしたもの、共同制作者から渡されたものもありました。そして、音楽の制作は、自分のものだけでなく、人から依頼された物もあり、クライアントから渡された音素材もあります。

依頼されて制作している場合は、複数バージョンを作った後に、レビューに出して、レビューの後に任意のバージョンから制作を再開する必要が出てきたりします。ここでバージョン管理という概念が必要になりました。

ただ、当時はバージョン管理の機能がなかったので、僕はプロジェクトを丸ごとコピーして、ファイル名でプロジェクトバージョン管理したりしていました。ただ、これの管理がなかなか辛い。特に、途中から編集したりすると、結局どれが最新か分からなくなったりするわけです。辛い。

この問題を僕は解決したかったりしたんですよね。そして時代は流れて、現在では、僕が使っているStudio Oneと言うDAWにはバージョン管理機能がついていて僕はこちらを使っているので、僕の問題は解消されました。

www.mi7.co.jp

ただ、せっかく集めた知識なので、誰かが再利用してくれたらいいな、と言う気持ちを込めて、ここに書きました。

ではでは

*1:ちなみに「この情報は害悪だな」とか「この主張は恥ずかしいな」と思った記事を整理するのが目的なので、その記事は、すでに非公開にしています

*2:映像データは、もうちょっと工夫が必要かと思いますが、本記事では、詳しく話しません

ソフトウェア開発の観戦とエッセイ

ちょっと古い本だけど、面白い本を見つけたので、書いておきます。

見つけた本はこちら。

BEST SOFTWARE WRITING

BEST SOFTWARE WRITING

  • 発売日: 2008/02/21
  • メディア: 単行本(ソフトカバー)

何が面白いか、を一言でいうと、普遍的な息の長いテーマを扱ってるところです。日本語版は2008年に出版されているけど、僕は今でも読む意味があると思っています。

いや、どうかな。とりあえず、僕は読んでいて楽しいと感じていて、ソフトウェアに関するエッセイが好きな人は読むと楽しめるように思います。と言うわけで読みながら読んでいる話を備忘録に書いています。

この本を読んだからと言って、何か新しいテクノロジーが扱えるようになるわけじゃないし、給料があがるわけでもないと思います。

なんというか、小説を読んだから何かができるようになるわけではない、という話に近い。ただ、この本を読むとソフトウェア開発者としての生活が、少し充実するかもしれません。

じゃあどんなことが書いてあるのか、という話になりそうなので、文章を一部引用して書いておきます。

プログラミングの世界では、毎日気付かれることなく戦争が行われている。それは人間とコンピュータサイエンティストの間の戦いだ。それはシンプルでルーズでしなやかで人間的なコードの書き方を望む人と、クリーンで明瞭ではっきりしていて正確なやり方でコードを書くことを望む人の戦いだ。それはPHPとC++/Javaの間の戦いだ。そしてかつてはCとdBASEの間の戦いだった。

この文章はP25に書いてあります。

今はPHPとC++/Javaの間の戦いではないと思いますが、近い対立はあるように思います。

その構図や議論を少し離れて見ながら、どうなるのかを考えながら見たり何かを応援するのは、楽しさがあります。

それは、おそらく、野球ファンがプロ野球を観戦する楽しみ方に近い気がします。

僕は、自分が使っている技術やシステム、サービスの開発背景や経緯、その途中の意思決定などなどの記録を読んで、ふむふむ、とするのは、割と好きな方ではありますが、その活動の亜種ですかね。

ソフトウェアやシステムは有機的にできていますが、その構成要素や仕組みを知って、ナルホド、という気持ちなる遊びです。

pytestで一時的に失敗を許可する

誰かのための備忘録です。あと、日本語の技術記事を増やそうかな、とも思っています。

pytestでテストを書きつつ、コードを修正していた際、既存のテストが失敗することはあります。

で、たくさんテストが失敗しすぎて、結果が見にくいと感じることもあります。

そういうときに、一時的にあるテストケースのテストの失敗を許容する書き方があります。

import pytest

@pytest.mark.xfail
def test_func():
    assert False

こんな感じです。 @pytest.mark.xfail を書くと、「このテストは失敗する」ということをマークすることができます。

詳細は、ドキュメントをどうぞ。

docs.pytest.org

他にも pytest.mark.skip とか pytest.mark.skipif とかもあります。

例えば、先日紹介したpytest-watchでテスト回しているときに、リファクタリングの修正を入れたらテストが大量にこけるようになったて、テスト一つ一つに対して、修正を検討しないといけないんだけど、まとめて検討しにくいときに使ってたりします。

複数の問題が絡まっているときも、問題を一つずつ解消していきたいので、原因を確かめて、原因を認識したテストケースは修正を後回しにするために、xfailをつけたりしてます。

pytestでクラスやメソッド指定でテストを実行することもできますが、できればpytest-watchである程度の範囲をまとめてテストしながら修正していきたいので、そんな進め方をしてたりします。

ファイル更新時にpytestを自動実行する

誰かのための備忘録です。

Pythonでテストを書くときに、pytestを使うことはよくあります。

で、ファイルを更新した後にpytestでテストを実行したいこともよくあると思います。

そういうとき、ファイル更新を検知して、自動でpytestを実行してくれるツールがあります。

pypi.org

使い方は簡単です。

pytestを実行している開発環境で、pip install してptwというコマンドを実行するだけです。

$ pip install pytest-watch
$ ptw

ptwを実行するとファイルの監視が始まります。

僕は、コードを書く際、技術的な課題が概ね解決できそうなイメージができたら「とりあえず、一気通貫の入出力だけ確認するユニットテストを書く。その後は、pytestを自動実行しながら良い感じにリファクタリングしつつ、細部のテストを追加していく」という進め方をすることがあります。

そういうとき、pytest-watchを起動しておくと、便利です。「さっきまで動いていたけど、いつの間にか動かなくなった」という問題を避けやすくなります。

dockerで開発している人は、以下の話が参考になるかもです。

https://github.com/joeyespo/pytest-watch/issues/91

と言いつつ、僕は、以下のページで紹介されているwatchdogを使いつつ、自分でdockerのテストコマンドを実行してたりします。

qiita.com