質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.02%

テストのためにメインのコードが見づらくなるのは皆諦めてるもの?

解決済

回答 11

投稿 編集

  • 評価
  • クリップ 11
  • VIEW 9,449

lazex

score 420

一般的なオブジェクト指向言語全体に言えることに言えることで、言語ごとにこういうのあるとか聞けると良いかなと思ったのでタグは色々つけています


ひとつめですが、 static method にするか、 instance method にするかについです

個人的には instance method は this のプロパティや他の instance method を参照するもののみで、インスタンスが持つデータへのアクセスが不要で引数だけから返り値が決まるもの(シンプルなものだと 2つの引数を足す add など)は static にしたいです
プロパティを参照しないものは static に分かれていたほうが見やすく、知らないクラスを見たときにも、このメソッドはプロパティ参照しないことがわかるのはいいことだと思います

しかし、知人から聞いたところテストを考えるとプロパティの参照がなくても instance method にした方がいいとのことでした
その理由は、 static にするとそのメソッドが呼ばれることが決まってしまうが、instance method であればインスタンスをモックに置き換えることで、テストに都合が良いようにできるというものです

add みたいなシンプルなものは不要ですが、返り値のデータが大きく(複雑な構造のオブジェクト)なりがちでそれを使う側のテストではシンプルなデータのほうが確認し易い場合、単に処理に時間がかかる場合、細かい仕様が決まってなく中身が未完成だけど使う側はテストしておきたいとき、などを考えると一理あるように思えます

しかし、テストは作るアプリケーション単体には必要なものでなく、作る側が楽に確認するためのものであり、テストだけのためにほぼ全てのメソッドを static method から instance method にするようなプログラムを見づらくすることは避けたいです

テストのしやすさをとるか、アプリのプログラム単体を見てわかりやすくなるようにするかどちらかをとるしかないものでしょうか?
みんな仕方なく、static でいいものも instance method にしているのでしょうか


2点目です
こっちはC#固有のものかと思います
上で書いたようなモックにインスタンスを置き換える場合です

AクラスがBクラスのインスタンスをもつときに、BをBを継承したB2クラスに置き換えます
Bクラスで各メソッドが virtual 指定されていなければ、override でなく new になり、Aクラス内のBがB2であろうと、Bクラスとしてメソッドが呼ばれるのでB2クラスでなくBクラスのメソッドが呼び出されます

ほとんどのクラスはどこかのクラス内で保持される思うので、テストを考えるとほぼ全部のメソッドがテスト以外に意味もなく virtual になります

有名らしいMoqというライブラリも virtual つけないといけないそうですし、これについては他に方法はなさそうです

テストのためだけに全部に virtual つけていくのが良い書き方とはとうてい思えないのですが、みんな諦めて書いてるものなのでしょうか

 謝辞

思った以上にたくさんの回答いただき驚きました
オブジェクト指向って難しいですね
いつまでもオープンのままにしておくのもどうかと思ったのでこのあたりで終了とします
ベストアンサーはすごく迷ったので、一番高評価が多かった回答にしました

ありがとうございました

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 11

checkベストアンサー

+14

「ひとつめ」

テストのためにインスタンスメソッド化するのではないのです。
疎結合にするためにインスタンスメソッド化し、疎結合化した結果としてテストもしやすくなるものなのです。

各クラスがスタティックメソッド群に依存しきってしまっていたら、クラスそれぞれを取り出して部品として扱うことは適わなくなります。それを

  • スタティックメソッド群をインスタンスメソッド化し
  • そのクラスはそれ用のインターフェースを実装した形にし
  • 利用する側のクラスはインターフェースへの参照だけ持ってそれに対してアクセスする

という形にすることでクラスからメソッドへの結合を引きはがせる、という話です。これによりメンテナンス性、分業しやすさ、クラスの性質の把握しやすさが向上します。テストもしやすくなっています。

「ふたつめ」

AがB型の参照を持つのではいけません。BのインターフェースをIBへ抜き出し、B implements IBの形にします。AはIB型への参照を持ってアクセスします。そしてテスト用のモックはIBを実装する形で作るのです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/05/21 22:08

    > 飛び先がわからないので処理を追えません
    これは私も感じたことあります
    疎結合に積極的にしようと感じられない1つでもあります

    > まず第一には再利用性です。
    なるほどです
    メリットについてはわかりました
    > 絶対視も軽視もせず、要件と必要性をみてバランス取っていこう
    どこで疎結合をとるか、とらないかなかなか難しいですね
    そこで「テストを理由」に疎結合をとるかを考えると当初の疑問に戻るので、
    とりあえずアプリケーションのコードだけをみて、「再利用する可能性があるか」を基準に考えてみようかと思います

    もしよければyubaさんの場合はどういうものは疎結合にする・していないかの具体例を教えてもらえるとうれしいです

    キャンセル

  • 2017/05/21 22:25

    私も偏っていてあんまり参考にならないと思います。
    というのは、疎結合を重視するのはJavaの価値観というところがあり、見た目は似た言語のC#の世界ではそこまでうるさく言われないものなんですけど、私はC#書くときにもまず「引きはがしポイント」から設計を考え始めてしまうくらいには疎結合脳なので。

    だからこれは具体例というよりは私の頭のおかしさの実例と言うべきなのですが、
    http://qiita.com/yuba/items/f52f90c4bd249d24b7d6

    キャンセル

  • 2017/05/23 22:09

    具体例ありがとうございます
    参考になりました

    キャンセル

+8

こんにちは。

経験的に「不必要な依存はしない方がよい」という原則は結構頑張って守った方が信頼性の高いプログラムを開発できると思います。
例えば、なるべくprivateにするとか、グローバルにアクセスできる変数はなるべく減らすなどです。
この原則に則ると、instance変数に依存していないstatic methodを、instance methodに変更して依存させるのは、ナンセンスと思います。
逆にいうと、テストしやすいからprivateにしないでpublicにしましょうと言っているのと同じように聞こえてしまいますね。

一部のメソッドだけを本番コードに影響しないように置き換えるって結構難しいですが、そもそも本番コードの設計レベルに影響するような置き換え方法は「無し」と思います。従来通りの泥臭い方法で置き換えるしかないのではないでしょうか?


【追記】
ちょっと質問の主旨から外れますが、instance methodの方が良いと言っている人も少なくないことにちょっとびっくりして、考えてみました。

オブジェクト指向プログラミングって非常に強力です。一般に手続き型フログラミングより適切である場面が多いです。(直感的には95%くらい? もしかすると99%くらいかも。)

そして、instance methodはオブジェクト指向プログラミングの代表的な仕組みの一つであり、static methodは昔からある手続き型プログラミングの代表格です。
なので、一般的には手続き型よりオブジェクト指向型の方がよいよと言う意味で、instance methodを推奨している人も居るような気がします。

一般論では全くその通りと思います。もしも、static methodが異様に目立つプログラムを見たら、オブジェクト指向を使いこなせないプログラマーが作ったのかな?とか思うかも。
しかし、ご質問のケースはstatic methodの方が設計的に適切な場合の話と感じたので、上記の議論には特に触れませんでした。

オブジェクト指向プログラミングが適切なケースは非常に多いので、結果としてinstance methodを使った方が適切な場面は多いと思います。しかし、手続き型プログラミングが適切な場合が皆無というわけではないのでその時にstatic methodを使った方が良い場面も少しはあります。後者を否定するとなかなか悲惨なプログラムが出来上がります。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/05/21 21:33

    そういう意味でしたか

    テストのためにifを作る、というのは出来る限り避けたいものですが、intance method化やpublic化などをしたことで別の問題がでてしまう可能性を考えるとしかたないですよね

    キャンセル

  • 2017/05/21 22:08

    そういうことですね。
    テストのためのif文は確かに嫌なものですから、static methodのままですげ替える良い方法が見つかるとよいですね。

    キャンセル

  • 2017/05/24 21:52

    追記拝見しました
    場合に応じオブジェクト指向と手続き型の適切な方を選択するようにしたいと思います
    ありがとうございました

    キャンセル

+6

C# は詳しくないので、ぼんやりした回答になってしまいますが。

static method にするか、 instance method にするか

一般的に、何らかの状態を管理する目的でクラスは作成されます。
管理している「状態」に関係するメソッドがinstance method で クラス自身の何か、例えば生成の Factory method がほしい場合に static method となるので、悩む事はあまりありません。
悩む場合、そもそもメソッドを定義するクラスが妥当かを考える方が良いでしょう。

知らないクラスを見たときにも、このメソッドはプロパティ参照しないことがわかるのはいいことだと思います

利用する側が、プロパティを参照している / していないを意識する必要がある場合、そのクラスのカプセル化が十分でないことを示しており、クラスの責務や提供する機能が何かを再考するとよいです。

instance method であればインスタンスをモックに置き換えることで、テストに都合が良いようにできるというものです

モックのやり方は色々あり、特定のテスティングライブラリの機能にこだわる必要はありません。

テストで他のクラスとの依存関係をモックに差し替えたいと考えたなら、実際のアプリケーションとしてもその部分を疎結合にしたほうがよいことを示しています。
テスタビリティが上がるようにコードを書いたつもりで、読みにくいコードを書いてしまうことはあります。
しかしそれは単に読みにくいコードを書いてしまっただけで、普通に書き直せばよく、どちらかを諦めるという話ではありません。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/05/20 23:56

    > 一般的に、何らかの状態を管理する目的でクラスは作成されます。
    そのクラスのインスタンスを作るファクトリメソッドと状態を変更するメソッドのみなら問題ないように思えます
    私がstaticにしたいと書いたものはそのクラスでしかつかわれないような固有の処理の「関数」で、状態問わず引数から返り値を状態によらず変換するものなんです

    > 利用する側が、プロパティを参照している / していないを意識する必要がある場合
    意図としては利用する側の立場ではなく、他人が書いたコードを読む場合や自分が昔書いたコードを忘れた頃に読んで、そのクラスの全体象を把握したいときです

    > モックのやり方は色々あり、特定のテスティングライブラリの機能にこだわる必要はありません。
    なるほど
    他の回答者さんの回答をみるとJavaやPythonはこういう問題も対処できるようですし、これがオブジェクト指向におけるテストの唯一の方法ではないですね

    キャンセル

  • 2017/05/21 09:49

    いかんせん、具体的なコードがないので話がかみ合っていないことを承知で

    > そのクラスでしかつかわれないような固有の処理の「関数」で、状態問わず引数から返り値を状態によらず変換するもの

    その「関数」が非常に単純なものであれば、そもそもテストを書く必要はないです。
    private static なメソッドとして好きにすればよいでしょう。

    テストを書かなければ不安になる程度に長いコードが、クラスの状態にまったく関係なく、static なメソッドとしてクラスに実装されている場合、
    クラスの設計に問題があるケースがほとんどです。その長いコードの責務を受け持つべきクラスを抽出することを検討しましょう。

    > 他人が書いたコードを読む場合や自分が昔書いたコードを忘れた頃に読んで、そのクラスの全体象を把握したいとき

    確かに、static メソッドになっていれば、そのクラスのフィールドを変更しないことが読み手にわかりますが、動機付けとしては弱いです。
    個人的には「メソッドの置き場所を考えるのが面倒なので、このクラスに突っ込んでおけばいいや」的な印象を受けます。

    キャンセル

  • 2017/05/21 21:50

    >具体的なコードがないので
    こちらわかりづらくすみません
    特定言語というよりオブジェクト指向の考え方みたいな意味で質問したかったので特定言語での例は控えました

    >動機付けとしては弱いです
    > static であるメリットについて、質問文の内容で共感を得ることは非常に難しい
    staticというか状態を考慮せず副作用起こさないことが保証されていることは、「変更するつもりのないものをgetterのみやconstにする」などと同じで読みやすさで重要に思うので、状態に触れないかつそのクラスに関わる処理はstaticにするのは私としてはできるだけそうしておきたいものです

    ですが、そう感じず困らない人もいるわけですし、コードの読み方について見直すという考え方もありかもですね

    キャンセル

+5

僕は一応C#でごはん食べてます。

回答1.static メソッドをわざわざ instance メソッドにすることはありません。
あるクラスに対して固有なものであっても、staticメソッドは混在しないようにします。
他の方の回答へのレスでファクトリメソッドを例に挙げていますが、ファクトリメソッドはファクトリクラスに纏めて外部化すべき部分です。
そのようにしていくと、最終的にstaticメソッドとinstanceメソッドの共存は無くなるはずです。

回答2.virtualが必要なMockライブラリを使いません。
Moq以外のライブラリを使えば防げる、という他の回答にあるように、モック生成という目的に手段の実装レベルが追いついていないがために起きた不幸です。
まだまだな部分もあるかもしれませんが、今ならinterfaceさえ用意すれば簡単にモックを作れます。例えばNSubstituteだったりFakeItEasyを調べてみるといいです。

質問がでっかすぎて小さなレスポンスが僕の脳みそだと書けません。
こういうの熱く長文書くと間違ってたら恥ずかしいから嫌だなぁって思いますが…
コードこみこみ100行超過して回答をレスしていいならコメントくれれば追記します。
とりあえず、実装したメソッドのテストカバレッジ100%を目指すとか、〇〇を使うが社内ルールだとどうしようもないんですが、そうじゃない場合、ユニットテストのためにコードを捻じ曲げる前に正しい方法が見つかると思います。

着目してることは正しいと思います。問題はたぶん、クラスの粒度が荒すぎるんです。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/05/24 11:05 編集

    そういえば他のコメントで、オブジェクトの内容を参照しないからstaticっていう話がありましたが、他オブジェクトと交流する時点で私はこの考えには否定的です。

    interfaceを作成すると明らかになることですが、interfaceを継承したオブジェクトには内部状態を見ないメソッドがしばしばあります。例えば、Is〇〇という状態判定メソッド、例えばIsReadOnlyは常にtrueだったりfalseを返しますが、このメソッドがstaticにならないのはなんとなく感覚で分かりますよね。
    これは「今たまたま内部状態に影響を与えない/受けない」メソッドになっているだけ、というような考え方ができます。

    基本的にオブジェクトの中身の設計に依存せず、内部状態を参照する可能性が将来にわたってある、と考えることができます。このようなメソッドの場合、staticメソッドにするのは当然誤りになりますよね。単一種のクラス設計になっていると勘違いしがちですが、何かのオブジェクトに依頼することが形式として自然であれば、それは内部状態の参照の有無に関わらずinstanceメソッドであるべきです。
    そうしなければ変更に対して開いておくことができないからです。

    interface経由の処理を実装していれば、自然とアップキャストすることになるのでこの点に対する感性は変わってくると思います。

    キャンセル

  • 2017/05/24 21:30

    > 内部状態を参照する可能性が将来にわたってある
    なるほど
    IsReadOnlyだとそのオブジェクトの readonly プロパティを参照するのでthisを使いますが、Array.IsArrayみたいな引数を純粋に判定するメソッドとか、どうやっても状態を見る必要が思い浮かばないのもありますよね
    今のところすっきりはしないのですが、こういうのでも「状態を参照する可能性は0じゃないんだ」と考えてしまうというのがオブジェクト指向なんですかね・・・

    なかなか難しいです

    キャンセル

  • 2017/05/25 11:39 編集

    オブジェクト指向だからそうする、っていうより、オブジェクト指向だと「そうなる」というべきです。

    あるListをWrapして内部状態を変更する操作全てを禁止し、読み取り専用リストを作ることを考えてみてください。このような変更を加える場合、ReadOnlyプロパティは内部にWrapしたListのReadOnlyに関わらずtrueでよくなります。あえて「リストの状態を変更する操作を禁止する」ことでReadOnlyに変更するわけですから、そもそも元のCollectionはReadOnlyプロパティがfalseなはずです。
    ※実際にこれを行うReadOnlyCollectionというクラスがあります

    ListのReadOnlyプロパティは元々そういうシナリオが存在することを前提に追加されているので、内部ListにDependantな実装ではIsReadOnlyは内部のリストの値を外部に返し、内部Listを拡張する場合(読み取り専用に変化させる)ではReadOnlyは参照しなくなります。

    Array.IsArrayはC#のメソッドにはありません。IsArrayはTypeに紐づくインスタンスメソッドです。
    String.IsNullOrEmptyメソッドが外部にあるのは、その方が低コストで済むということの他に、オブジェクトがnullであることを調べる方法はstaticメソッドにするしかないからです。
    また、stringオブジェクトは組み込み型で代替の必要ない実装であることから強依存できます。
    stringオブジェクトは直接staticメソッドを持つ条件を満たしています。

    オブジェクトの実装を切り替える可能性があるところではinterfaceと、そのinterface用のstaticメソッドという組み合わせになり、interfaceの実装クラスは切り離され直接的に依存しなくなるべきです。
    実装クラス側に後の処理で使われるpublic staticメソッドを持つのはNGです。それをすると別の実装を作っても、元の実装クラスの参照を切ることができなくなります。

    これらの条件を全て繋ぎ合わせると、mock化される対象となるクラスは必然的にpublicなstaticメソッドを持つことはありえなくなります。

    キャンセル

+4

>プロパティを参照しないものは static に分かれていたほうが見やすく、知らないクラスを見たときにも、このメソッドはプロパティ参照しないことがわかるのはいいことだと思います 

そのメソッドは本当にそのクラスメンバとして実装するのが妥当でしょうか?

インスタンス内部の状態に全く依存しないということは、演算子や書式化など、本来のクラスの責務とは少し異なる目的を持ったメソッドである可能性が高いんじゃないでしょうか?

そういったメソッド、例えば XXX クラスのファクトリメソッドであれば XXXFactory クラスに追い出して、本来のクラスの責務とは別物としてテストを書くことが出来ます。

また、C# であれば拡張メソッドとして記述することで、やはりクラス本体から切り離して記述することが出来ます。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/05/21 00:08

    > そのメソッドは本当にそのクラスメンバとして実装するのが妥当でしょうか?
    ちょっとした演算などでもそのクラスでしか使わないだろう独特な演算ならばそのクラスのメソッドとしたいです
    そのクラス以外でも使う可能性がある汎用のメソッドならUtilityなどの名前でstatic class を作ってそこにまとめるようにしてます

    ただこの Utility にしたところで、Utility.Xxxx というメソッドをモックに置き換えてテストしたいとなれば Utility は static でなくそれぞれを instance method にしないといけないので、問題は変わっていないと思います

    キャンセル

+3

個人的な指針ですが

 1つ目

私の場合、基本的にinstanceクラス設計します。
拡張メソッドを作るときにはstaticクラスとしますが、それ以外はinstanceクラスとして設計します。

オブジェクト指向として考えた場合、
・クラスの継承
・インターフェイスの実装
は機能を交換可能なものとして実装するための設計です。
そう考えたときに、staticクラスでは、交換可能な実装になりません。
今、交換が不要でも、将来交換が必要になるかもしれない場合、
instanceクラスとして設計しておくことがメリットになると思います。

この辺の話はSOLIDオブジェクト指向の原則を意識し始めると自然とそうなると思います。

 2つ目

ちょっと回答がずれますが、継承よりinterfaceを利用することを意識しています。
何でもかんでも継承するとおっしゃるようにvirtualを付けた・付けないで問題が発生します。
継承を深くするより、機能を分断しクラスを設計し、それをまた集合・集約として利用する方が、
再利用性が高くなると思っています。

他の方もおっしゃっているようにクラスの粒度が大きい、単一責任の原則(SRP)に沿っていないのだと思います。

もう一つ、テストのためにコードが見にくくなることを諦めていません・諦めてはいけません。

ご参考になれば幸いです。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/05/23 21:48

    拡張メソッドを作る目的以外では すべてのクラスが interface をもち、 そこに static なメソッドが無い状態ということですよね
    クラスをどう分割してもどこかにでてくる「状態を考慮しない関数」をinstance methodにすることが避けたいものですが、それが「テストのため」でなく「交換可能」別の回答にある疎結合にすることにメリットを見い出せばそこまで気にならなくなるかもしれません

    interface は generics 使うとか必要にならなければあまり作らないものだったのですが、interface を勧めてくれる方が多いのでinterfaceについても考えてみます

    キャンセル

+2

Pythonはどちらも該当しなさそうです。

ひとつめ
最近のバージョンのPythonであればmockライブラリが標準で入っているので、テストを意識せずに好きに書いたコードでもシンプルに実装されていれば簡単にテストできます。

ふたつめ
Pythonはクラス名.メソッド名として実行するべきメソッドを明示的に指定できますし、逆にダックタイピングで実行対象を制限せずにself.メソッド名ともできます。ので、実装時にテストのことを考える必要はこの点でもありません。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/05/21 00:02

    Pythonは本格的に使ったことがなくテストの知識はほぼないのですが、
    言語自体がテストを意識しないようになっているものはいいですね

    ふたつめですが、クラス名でなくselfにしておけばオーバーライドされていればそっちが使われる
    ということですよね

    やはり継承しても親クラスに手を入れて置かなければ真にオーバーライドできないのはC#くらいの特殊なしくみですよね

    キャンセル

  • 2017/05/22 10:39

    テスト機構で言えばPythonにはdoctestなんてものも標準で用意されており、この辺りは言語の思想を強く表していますね。

    キャンセル

  • 2017/05/23 22:08

    ドキュメントにサンプルとしてテスト書いておくというのは変わってますよね
    関数が長くなるデメリットがありますが、使い方を知りたいときに別のテストファイルを探さなくてもいいメリットもありますし、引数も返り値もシンプルな型ならありかなって思います

    キャンセル

+2

質問が2つあるなら、質問を2つ作成して欲しいです。
他の方があとで検索しやすくなりますし、適切にベストアンサーが着きますし、回答者もちゃんと評価されるので・・・

一つ目の回答です。

すべてをstatic methodで書いてはいけないかという点についてですが、それだったらC#の基本的な文法を否定して、変な書き方になるので、他の言語で書くとよいと思います。F#だったらC#より違和感がないかもしれません。

また、関数型言語の場合でも複雑な操作を行う関数は引数が多くなります。その為、バインドや関数渡しなどを使い引数を少なくしてわかりやすくします。Pythonは暗黙のself(this)を最初の引数としてつかっていることからも分かる通り、staticにしようとしまいと同じだけ引数をつかっているのです。(ノイマン型のCPUをつかっているので基本原理は同じと考えてもよいかもしれません。)

オブジェクトは副作用を持つという点について問題がありますが、その問題はオブジェクトをインスタンス後に状態変更出来なくするオブジェクトにするということでこのようなものをimmutableと呼びます。

immutableに出来なくても、できるだけ状態を持たないようにすることで複雑化を避けることができます。

また、javaでMOJOと呼ばれ、.netではPOCOと呼ばれるオブジェクトがあります。これは、継承とかややこしいオブジェクト設計は避けようという動きです。

テストの問題であれば、テストが複雑になる原因がそもそも”プログラムで解決しようとする問題”(以下、問題と呼ぶ)の複雑さにある場合があります。問題が複雑であればテストは複雑になるので、どのように問題を分解するべきかという事では無いでしょうか?

二つ目の回答は、モックを使う場合私は、インターフェイスを使います。現行のオブジェクトをインターフェイスに置き換えるのは面倒ですが、継承を使うとそれはそれでモックオブジェクトの作成が面倒では無いでしょうか。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/05/21 21:29

    やりたいことがしやすい言語を選ぶというのも可能であればありな方法ですね
    static にしようとしてるところは副作用なく参照透過なものなので、関数型な言語と言う選択も考えてみます

    staticであろうと引数のプロパティを変えて状態を変えるのならthisあるのと一緒というのはそのとおりですね
    何が理想か、が自分の中でも定まらなくなってきました・・・

    2つめですが、インタフェースとvirtual化して継承のどちらも面倒で、テスト以外にインタフェースとして必要ないのにインタフェースができたり、有名らしいモックライブラリでvirtualが使われていたので継承の方を使いました


    キャンセル

  • 2017/05/22 10:28

    2つ目のvirtualの話ですが、すべてのメソッドにvirtualを付けるとしたらという前提の話でした。必要のないのにinterfaceを作る問題は、必要がないvirtualが大量につくのに比べたら”まし”だという感想です。

    対象がすくなけれはvirtualでもいいかもしれませんが、わたしなら、クラス設計を見直し、このような箇所を局所化することを検討します。

    テストが設計に影響するのは本末転倒と考えるかもしれませんが、私はテストが設計に良い影響を与えるという点について信じていて、何らかの境界がある部分にモックが必要なんだとおもっています。とはいえ実際のコードを見ないとなんとも言えないのですが・・・

    キャンセル

+1

staticメソッドのテストはpower mockなどのフレームワーク使えば良いだけの話ですね。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/05/20 23:26

    Javaだと power mock でstaticメソッドも置き換えれるのですね
    アプリケーション側はそのままでテスト側だけで対処できるのはいいですね

    キャンセル

+1

C#のモックライブラリーなどは詳しくないため、1つ目の問いにのみとなります。

既出かも知れませんが、テストではなく、オブジェクト指向設計というものが、オブジェクト(モジュール)間の結合強度を下げて、疎結合化するという目的を持った設計技法なので、基本としてインスタンスメソッドを作るようにしています。
(例外はありますが)

疎結合化して、同じ操作でも、オブジェクト毎に異なる振る舞いを行うことを、ポリモーフィズム(多態性)といいますが、これは、オブジェクトを設計する側ではなくて、使う側にとってメリットがあります。

例えば、ウィンドウ制御を行うGUIアプリを作成するような場合を例に挙げると、以下のようなことが出来ます。

Windowというオブジェクトがあるとします。
Windowを閉じる機能として、Closeという要求操作(メソッドなり関数なり、呼び方は言語によってまちまちです)があるとします。
これが、WebブラウザーのWindowなのか、はたまたテキストエディターのWindowなのかに関係なく、ウィンドウ制御側は、CloseというAPIを経由して、閉じたいWindowオブジェクトにウィンドウを閉じるように要求することが出来ます。
これが、所謂インスタンスメソッドといった呼び方をされるものです。

密結合でいいのであれば、ウィンドウ制御側は、Webブラウザーのウィンドウを閉じる操作(=staticメソッド)を呼び出したり、テキストエディターのウィンドウを閉じる操作をしたりしなければなりません。

適当なコードで表現してみると、インスタンスメソッドの場合、
(ちょっとだけC#風にしてみました)

Window window = new WebBrowser();
window.Close(); // ここではWindowのCloseを呼び出している
window = new TextEditor(); // window変数に破壊的再代入していますが、多態性のサンプルとして必要なのでご了承下さい(iPhoneで書くの大変なので)
window2.Close(); // ここではWindowのCloseを呼び出している

と出来ます。

対して、staticメソッドの場合、

WebBrowser.Close();
TextEditor.Close();

としなければなりません。

モック云々で言えば、モックライブラリー次第なので、staticメソッドだろうとモック化出来るので、テストのためではなく、汎用性を高めたり、疎結合化することで、不具合が出たときにモジュール差し替えるだけで修正出来る(Windowsのdllなんかをイメージするといいかも。Javaもクラスファイルの差し替えで同じこと出来ますし)のが、オブジェクト指向設計の基本的な考え方のひとつだったりします。

staticメソッドにも利点はありますが、staticメソッドは構造化設計の考え方とも言われたりする(使い方次第ではありますが)ので、オブジェクト指向言語で設計する際には、基本的には先ずはinterface(言語によってはtraitだったりprotocolといった機能)を用意して、そこに対して実装を行うようにしています。

長いのと、少し古いですが、次のスライドを読むと、疎結合化する意味などが掴みやすくなるのではないかと思います。(相当後のほうのスライドですが)
https://www.slideshare.net/mobile/MoriharuOhzu/ss-14083300

staticメソッドにも利点はあって、所謂Factoryメソッドパターンや、言語的にシングルトンオブジェクトパターンをサポートしていない言語で、シングルトンオブジェクトパターンを実現するような場合には、オブジェクト指向設計でも有用だったりします。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

C#でしたら、Fakes FrameworkやPrigを検討してみてはどうでしょうか。
staticだろうがモックできるようになりますよ。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/05/24 21:29

    ILレベルで書き換えするからstaticもモックできるというのはちらっとみたことありましたが
    これのことですかね

    使い方を見てみましたが、導入はやはり一手間かかりますね

    既存コードを書き換える手間が無いという意味ではstaticをモック化できるのが楽なので検討してみます

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.02%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる