fc2ブログ

.NETプログラミングの勘所 - インタフェースを有効利用しよう

 .NETプログラミングをする上で、押さえておきたいポイントは、インタフェースです。.NETプログラミング以前はCOM( Component Object Mode )プログラミングが主流でした。しかも、.NET FrameworkそのものがCOMで実装されています。COMプログラミングはいわば、インタフェースプログラミングのようなものであり、その流れを受けて.NETプログラミングでもインタフェースはいまだに重要です。
 もちろん、歴史的な理由だけで使用を勧めているのではありません。インタフェースが役立つ理由が3点以上あります。.NETプログラミングをするならば、インタフェースはおさえるべきものなのです。これからその理由を解説します。
 その一、実装継承階層からの独立。オブジェクト指向プログラミングのフレームワークは複雑で、実装の継承を多用して作られています。それ故に、実装の継承階層を注目しがちですが、.NET Frameworkは、インタフェースの継承も多用されています。その理由はいろいろありますが、そのうちの一つが継承階層からの独立です。実装の継承は型にはまれば強力ですが、現実の問題が型にはまると限りません。現実世界では、階層からはみ出た問題も解決せねばなりません。そこで、階層的につながっていないオブジェクトを表わす手段が必要となってきます。その役割を果たすのがインタフェースです。インタフェースを使用知れば、より再利用性の高いプログラミングができます。
 その二、オブジェクトの特徴を示せる。オブジェクトには様々な特徴があります。しかし、それらオブジェクトに共通した特徴や特筆するべき特徴があります。それらオブジェクトの特徴を、プログラムで記述できれば、より高度なプログラミングができます。しかもその可能性は無限大です。インタフェースを実装したオブジェクトは、様々な局面で活躍します。
 その三、便利なインタフェースが既に用意されている。先ほど述べたように、.NET Frameworkには便利なインタフェースが沢山用意されていますし、インタフェースを利用する強力なメソッドも多いです。その恩恵を受けるために、ちょっとした手間をかけて、自分が作るオブジェクトに既存のインタフェースを持たせるべきです。そうすれば、.NET Frameworkの強力さを得られます。
 インタフェースをおさえて、快適な.NETプログラミングライフを楽しみましょう♪
スポンサーサイト



テーマ : プログラミング
ジャンル : コンピュータ

C#で関数型プログラミングを楽しむ♪

 真面目な事ばかり書いても飽きると思いますので、たまには遊び心があるプログラミングの記事を書きます。関数型プログラミングが大好きで、どうしてもC#で関数型プログラミングをしたい場合この様にすればよいでしょう。

using System;

class Piyo
{
    private string m_msg;
    public string Message
    { 
        get { return this.m_msg; } 
    }
    
    public Piyo( string msg ) 
    { 
        this.m_msg = msg;
    }

    public static Piyo AddPiyo( Piyo p )
    {
        return new Piyo( p.Message + "ピヨ♪" );
    }
}

class PiyoPiyo : Piyo
{
    public PiyoPiyo( string msg ) : base( msg ){ }

    public static PiyoPiyo AddPiyo( PiyoPiyo pp )
    {
        return new PiyoPiyo( 
            Piyo.AddPiyo( pp ).Message + "ピヨ♪" );
    }
}

class Program
{
    static void Main( string[] args )
    {
        string str = "C";
        Console.WriteLine(
            Piyo.AddPiyo( new Piyo( str ) ).Message );
        Console.WriteLine(
            PiyoPiyo.AddPiyo( new PiyoPiyo( str ) ).Message );
    }
}

 関数型プログラミングは、関数による戻り値でプログラミングを行います。ですが、通常(命令型)のオブジェクト指向プログラミングを行うとメソッドは副作用を生みます。そこで、関数型プログラミングに近づけるに、オブジェクトのインスタンスを受け取る静的メソッドを定義し、受け取ったインスタンスに変更を加えずに、新しいインスタンス生成して返す必要があります。あと、プロパティは読み取り専用にした方がよいでしょう。「何故、F#を採らない!」
 この様にすれば、副作用がない関数型プログラミング風のプログラミングを実現できます。もちろん、.NETで関数型プログラミングをしたいのであればF#を使えばよいの言うまでもありません。
 真面目な話を言うと、このテクニックは並行処理に向いています。並行処理の対象となるクラスは、この様に定義すればいいかもしれません。「何故、F#を採らない!」

テーマ : プログラミング
ジャンル : コンピュータ

.NETテストプログラミング入門7

 この記事は、.NETテストプログラミング入門6の続きです。前回はGUIプログラムのサンプル(WPF)を提示しました。今回はGUIプログラムをテストする方法を解説します。
 前回例として提示したGUIプログラミングのサンプルをテストするには次のようにします。

using System;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;

class WpfTest
{
    [STAThread]
    static void Main()
    {
        //型を取得(※AssemblyQualifiedNameを使用する)
        Type piyoType = Type.GetType( "PiyoWindow, WpfTest_Target, " +
            "Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" );

        //テストの準備
        Window target = ( Window ) Activator.CreateInstance( piyoType );
        StackPanel panel = ( StackPanel ) target.Content;
        TextBox box = ( TextBox ) panel.Children[ 0 ];
        Button btn = ( Button ) panel.Children[ 1 ];
        Label label = ( Label ) panel.Children[ 2 ];

        //値を設定してからクリックイベントを呼び出す
        string inputValue = "テスト";
        box.Text = inputValue;
        MethodInfo method = typeof( Button ).GetMethod( "OnClick",
            BindingFlags.NonPublic | BindingFlags.InvokeMethod |
            BindingFlags.Instance );
        method.Invoke( btn, null );

        //値をチェック
        string right = inputValue + "ピヨ♪";
        bool result = right.Equals( label.Content );
        Console.WriteLine(
                result == true ? "テスト成功" : "テスト失敗" );
    }
}

このコードを見れば、GUIのテストが意外と簡単である事が分かると思います。GUIのテストは通常のプログラミング以外のなにものでもありません。リフレクションとWPFを知っていれば自然に思いつく方法です。
 これはテスト対象が簡単である事も影響していますが、テスト対象がサンプルよりも複雑であっても、テストコードの行数が増えるだけで考えそのものは変わりません。GUIテストに於いて重要なポイントは3つしかありません。
 1つめのポイントは、非公開のクラスを呼び出す方法です。大概のアプリケーションは、そのアプリケーションしか使わない独自ウィンドウを公開したくありません。公開していないクラスを呼び出す方法は、.NETやJavaの場合はリフレクションです。他の言語の場合、違う方法でハックすれば同様の事が出来ます。アクセス修飾子の問題はテストに於いてよくある事なので、プログラマは非公開のクラスのインスタンスを生成する方法を習得するべきだと言えます。
 2つめのポイントは、イベントを発生させる方法です。GUIもただのプログラムです。人間がクリックせねば絶対に動かないわけではありません。それどころかコンピュータはOSの働きもあり、イベントを呼び出す相手が人間の操作なのかプログラムなのかを気にしません。どのようなGUIフレームワークにも、コードでイベントを呼び出す方法があるはずです。今回はリフレクションが簡単なのでそうしましたが、他のリフレクションがない言語でも同様の事が出来るでしょう。
 3つめのポイントは、仕様をはっきりさせる事です。どのコントロールが、どのようにして値を付け取り、どのような値を出力するのかを明確にせねばなりません。仕様が明確に定められていないとテストが出来ません。これはあくまでも私個人の感覚ですが、現場ではこの点を見過ごして、「GUIテストは難しいから人がチェックする」と言っている人が多いと感じています。確かにGUIの美的感覚をプログラムをチェックできません。ですが、全てのGUIプログラムの動作はチェックできます。テストできる部分は絶対にするべきです。GUIプログラムはテスト出来ないからバグがあるという言い訳はクライアントに通用しません。
 どうやら、GUIプログラミングはどう見えるのかばかりが意識され、プログラム的にどういう動きなのかを見過ごす傾向があるようです。該当しないチームも多々存在するでしょうが、そうでないプロジェクトチームはそもそもGUIプログラムのテストを実施しているはずです。
 駆け足でテストプログラミングについて書きました。この連載でテストプログラミングが通常のプログラミングである事が分かったと思います。この連載がテストは難しいと忌避する考えを変え、信頼性が高いシステムがつくられる一助になれば幸いです。

テーマ : プログラミング
ジャンル : コンピュータ

.NETテストプログラミング入門6

 この記事は、.NETテストプログラミング入門5の続きです。前回は静的プロパティが関係するクラスを、正確かつ並行的にテストする方法および、テストコードの原則について書きました。今回はテストが難しいとされているGUIのテストについて書きます。
 一般的にテストで難しいとされているプログラムは並行処理とGUIです。並行処理については前回述べましたので、今度はGUIのテストについての解説をします。
 先ずはテスト対象となるGUIのコードを見てみましょう。

using System;
using System.Windows;
using System.Windows.Controls;

static class Program
{
    [STAThread]
    static void Main()
    {
        SampleApplication app = new SampleApplication();
        app.Run();
    }
}

class SampleApplication : Application
{
    public SampleApplication()
    {
        this.Startup += ( object sender, StartupEventArgs e ) => 
        {
            PiyoWindow win = new PiyoWindow();
            win.Show();
        };
    }
}

//テストの対象となるクラス
class PiyoWindow : Window
{
    private StackPanel panel;
    private TextBox inputValueBox;
    Button piyoAddButton;
    private Label outPutValueBox;

    public PiyoWindow()
    {
        //Windowの設定
        this.Title = "テスト対象ピヨ♪";
        this.MinHeight = 150;
        this.MaxHeight = 150;
        this.MinWidth = 300;
        this.MaxWidth = 300;
        this.WindowStartupLocation = 
                WindowStartupLocation.CenterScreen;
        
        //各種コントロールの配置
        panel = new StackPanel();
        this.Content = panel;

        inputValueBox = new TextBox();
        inputValueBox.Text = "ここに文字を入力して下さい。";
        panel.Children.Add( inputValueBox );

        piyoAddButton = new Button();
        piyoAddButton.Content = "出力ピヨ♪";
        piyoAddButton.Click += ( object sender, RoutedEventArgs e ) => 
            outPutValueBox.Content = inputValueBox.Text + "ピヨ♪";
        panel.Children.Add( piyoAddButton );

        outPutValueBox = new Label();
        panel.Children.Add( outPutValueBox );
    }
}

このサンプルコードは、ボタンをクリックすると一番上のテキストボックスに入力した文字列に「ピヨ♪」を付け、一番下に表示されるラベルに表示するという実にシンプルなWPFプログラムです。
 このサンプルは単純ですが、GUIテストの本質を知る材料になります。答えを見る前に自分でテストコードをコーディングしてみて下さい。続く...

テーマ : プログラミング
ジャンル : コンピュータ

.NETテストプログラミング入門5

 この記事は、.NETテストプログラミング入門4の続きです。前回はテストを並行処理する場合における静的プロパティに関する問題点を書きました。今回は静的プロパティが関係するクラスを、正確かつ並行的にテストする方法および、テストコードの原則について書きます。
 先ずは解答となるテストコードを掲載し、そのテストコードを元に解説します。

using System;
using System.IO;
using System.Threading;

static class ConsoleTester
{
    private static Semaphore lockObj = new Semaphore(1, 1);
    public static bool ConsoleOutCheck(
        string right, Action proc, bool yield )
    {
        //ロック開始
        lockObj.WaitOne();

        //出力先を変えてテストを行いやすくする
        TextWriter tmp = Console.Out;
        StringWriter writer = new StringWriter();
        Console.SetOut( writer );

        //テスト対象を実行
        Thread.Sleep( 100 );
        proc();

        //出力設定を元に戻す
        if ( yield == true ) Thread.Yield();
        Console.SetOut( tmp );

        //出力値をテスト
        bool result = writer.ToString().Equals( right );

        //ロック解除
        lockObj.Release();

        //テスト結果を返す
        return result;
    }
}

class Piyo
{
    public void Greeting()
    {
        Console.WriteLine( "おはピヨ♪" );
    }
}

class HelloWorld
{
    public void FirstProgramming()
    {
        Console.WriteLine( "Hello World!" );
    }
}

class Test
{
    static void Main( string[] args )
    {
        //Piyoクラスのテストを実行
        string piyoMessage = null;
        Thread pt = new Thread( () => {
            Piyo piyo = new Piyo();
            string right = "おはピヨ♪" + Environment.NewLine;
            bool result = ConsoleTester.ConsoleOutCheck(
                right,
                () => piyo.Greeting(),
                false );
            piyoMessage = result == true ?
                "Piyoテスト成功" : "Piyoテスト失敗";
        } );

        //HelloWorldクラスのテストを実行
        string helloMessage = null;
        Thread ht = new Thread( () => {
            HelloWorld hello = new HelloWorld();
            string right = "Hello World!" + Environment.NewLine;
            bool result = ConsoleTester.ConsoleOutCheck(
                right,
                () => hello.FirstProgramming(),
                true );
            helloMessage = result == true ?
                "HelloWorldテスト成功" : "HelloWorldテスト失敗";
        } );

        //並行的にテスト
        pt.Start();
        ht.Start();
        pt.Join();
        ht.Join();

        //テスト結果を表示
        Console.WriteLine( piyoMessage );
        Console.WriteLine( helloMessage );

    }
}

以上のように前回のテストコードを少し改良するだけで、並行的にテストが出来るようになります。このテストコードはポイントが3つあります。
 1つめのポイントは、同期オブジェクトを使用し排他制御をしている事です。ConsoleクラスのOutプロパティのように静的プロパティを使用する場合、並行処理の結果を仕様通りにする為に排他制御をせねばなりません。複数のスレッドが同時に静的なプロパティの値を変更すると、静的な値に依存するクラスは整合性のある結果を出せません。詳しくは今後.NET並行処理プログラミングの記事を連載しますのでそちらの方を読んで下さい。
 2つめのポイントは、テストを実行するクラスのメソッドを静的にする事です。テストコードもまた普通のプログラムです。他者が理解しやすいように考慮せねばなりません。このテストは静的な値に依存するので、分かりやすいように静的メソッドにせねばなりません。そうしないとこのテストコードを書いていない人は、オブジェクト指向プログラミングは通常インスタンスを使用するので、インスタンスな値に依存するテストだという前提を持ちます。従って、注意を促すために静的メソッドにする必要があります。
 3つめのポイントは、テストを実行するクラスを静的にする事です。コンソールの入出力機能を使用するこのクラスは明らかに静的なものです。何故ならば、Consoleクラスの静的なOutプロパティが関係するからです。コンソールはそもそもグローバルかつ共有的なものです。それを他者に伝える為に静的なクラスでなければなりません。
 2つめと3つめのポイントは、テストを並行処理しない場合でも同じ事が言えます。テストコードを漫然とコーディングしてはなりません。テストの性質に応じたテストクラスを設計&実装せねばなりません。何故ならば、テストコードは仕様書としての役割も果たすからです。テストの性質と異なるテストコードはプログラマに誤解を与えます。意外とテストコードを意識しない人が多々見受けられます。しかしながら、テストコードは仕様を示す大切な資産です。よく考えてテストコードをコーディングしましょう。

テーマ : プログラミング
ジャンル : コンピュータ

.NETテストプログラミング入門4

 この記事は、.NETテストプログラミング入門3の続きです。前回は、関数型プログラミングの技法を使って、テストコードをより汎用的なものにする方法を解説しました。今回は、前回紹介したテストコードの問題点を解説します。
 前回紹介したテストコードにはある問題があります。それは、並行的にテストを行う時露呈します。

using System;
using System.IO;
using System.Threading;

class Tester
{
    public bool ConsoleOutCheck( string right, Action proc, bool yield )
    {
        //出力先を変えてテストを行いやすくする
        TextWriter tmp = Console.Out;
        StringWriter writer = new StringWriter();
        Console.SetOut( writer );

        //テスト対象を実行
        Thread.Sleep( 100 );
        proc();

        //出力設定を元に戻す
        if ( yield == true ) Thread.Yield();
        Console.SetOut( tmp );

        //出力値をテスト
        bool result = writer.ToString().Equals( right );

        //テスト結果を返す
        return result;
    }
}

class Piyo
{
    public void Greeting()
    {
        Console.WriteLine( "おはピヨ♪" );
    }
}

class HelloWorld
{
    public void FirstProgramming()
    {
        Console.WriteLine( "Hello World!" );
    }
}

class Test
{
    static void Main( string[] args )
    {
        //テストの準備
        Tester tester = new Tester();

        //Piyoクラスのテストを実行
        string piyoMessage = null;
        Thread pt = new Thread( () => {
            Piyo piyo = new Piyo();
            string right = "おはピヨ♪" + Environment.NewLine;
            bool result = tester.ConsoleOutCheck(
                right,
                () => piyo.Greeting(),
                false );
            piyoMessage = result == true ? 
                "Piyoテスト成功" : "Piyoテスト失敗";
        } );

        //HelloWorldクラスのテストを実行
        string helloMessage = null;
        Thread ht = new Thread( () => {
            HelloWorld hello = new HelloWorld();
            string right = "Hello World!" + Environment.NewLine;
            bool result = tester.ConsoleOutCheck(
                right,
                () => hello.FirstProgramming(),
                true );
            helloMessage = result == true ? 
                "HelloWorldテスト成功" : "HelloWorldテスト失敗";
        } );

        //並行的にテスト
        pt.Start();
        ht.Start();
        pt.Join();
        ht.Join();

        //テスト結果を表示
        Console.WriteLine( piyoMessage );
        Console.WriteLine( helloMessage );
    }
}

※このサンプルコードは、並行処理による問題が発生しやすいようにしています。
 このサンプルを実行すれば、前回紹介したテストコードは並行処理時に問題がある事が分かります。もし、問題が発生しない場合は、Sleepに引き渡す値を大きくしてみましょう。
 この問題が発生する原因は、静的プロパティを使用している点です。静的プロパティであるOutプロパティを静的メソッドで設定しているため、個々のスレッドの出力ストリームの変更が、他のスレッドに影響を与えています。この状態ではまともにテストが出来ません。
 今後並行的にテストを処理する機会が多くなるでしょう。ですから、テスト対象となるクラスが持つ性質をよく考えなくてはなりません。問題の解決方法は次回解説します。続く...

テーマ : プログラミング
ジャンル : コンピュータ

.NETテストプログラミング入門3

 この記事は、.NETテストプログラミング入門2の続きです。今回は、前回紹介したオブジェクト指向なテストコードを、関数型プログラミングの流儀を持って改良します。
 前回のテストコードは、シンプルを前提にすると、オブジェクト指向プログラミングでは限界に近いと思います。しかし現代的なプログラム言語には、もっとスマートな方法があります。それは、関数型言語の要素を取り入れる事です。
 関数型プログラミングの考え方を取り入れると、いとも簡単にテストを行うための前提が減ります。

using System;
using System.IO;

class Tester
{
    //関数(この場合はプロシージャ)を渡せばいい
    public bool ConsoleOutCheck( string right, Action proc )
    {
        //出力先を変えてテストを行いやすくする
        TextWriter tmp = Console.Out;
        StringWriter writer = new StringWriter();
        Console.SetOut( writer );

        //テスト対象を実行
        proc();

        //出力設定を元に戻す
        Console.SetOut( tmp );

        ////出力値をテスト
        bool result = writer.ToString().Equals( right );
        return result;
    }
}

class Piyo 
{
    public void Greeting()
    {
        Console.WriteLine( "おはピヨ♪" );
    }
}

class HelloWorld 
{
    public void FirstProgramming()
    {
        Console.WriteLine( "Hello World!" );
    }
}

class Test
{
    static void Main( string[] args )
    {
        //テストの準備
        Tester tester = new Tester();

        //Piyoクラスのテストを実行
        Console.WriteLine( "これからPiyoテストを実行します。" );
        Piyo piyo = new Piyo();
        string right = "おはピヨ♪" + Environment.NewLine;
        bool result = tester.ConsoleOutCheck(
            right,
            () => piyo.Greeting() );
        string message = result == true ? "テスト成功" : "テスト失敗";
        Console.WriteLine( message );
        Console.WriteLine();

        //HelloWorldクラスのテストを実行
        Console.WriteLine( "これからHelloWorldテストを実行します。" );
        HelloWorld hello = new HelloWorld();
        right = "Hello World!" + Environment.NewLine;
        result = tester.ConsoleOutCheck(
            right, 
            () => hello.FirstProgramming() );
        message = result == true ? "テスト成功" : "テスト失敗";
        Console.WriteLine( message );
        Console.WriteLine();
    }
}

このテストの要件はあるコンソールへ文字列を出力するメソッドの正しさをチェックしたいという事です。ならばテストコードは、任意のメソッドが実行できればよいのであって、オブジェクトに拘る必要は何もありません。
 なお、このテストコードにおいて、Actionデリゲート引数が最後になっているのは、Funcデリゲート引数などのオーバーロード(多重定義)メソッドを増やす事が予測できるからです。正しい値を後にすると読み難いので、オーバーロードされると予測できるパラメータは最後にします。
 このテストコードで完成と思った人も多いかと思います。ですが、これはまだ不完全なテストコードです。コンソールの性質を考慮すると十分とは言えません。まだ問題点があります。その問題点は・・・次回へ続く。  

テーマ : プログラミング
ジャンル : コンピュータ

.NETテストプログラミング入門2

 この記事は、.NETテストプログラミング入門1の続きです。今回は前回紹介したテストコードを、オブジェクト指向プログラミングの流儀に従って再利用できるように改善します。
 前回述べたようにテストコードが長く再利用できない状態は、オブジェクト指向プログラミングとしては問題です。具体的に言うと、特定のクラスに依存している事が問題です。どのクラスのメソッドであってもテスト出来るように改良せねばなりません。この場合、オブジェクト指向プログラミングの考え方では、インタフェースを使用してテストコードを改良します。

using System;
using System.IO;

interface IConsoleOut
{
    void MessageOutPut();
}

class Tester
{
    public bool ConsoleOutCheck( IConsoleOut target, string right )
    {
        //出力先を変えてテストを行いやすくする
        TextWriter tmp = Console.Out;
        StringWriter writer = new StringWriter();
        Console.SetOut( writer );

        //テスト対象を実行
        target.MessageOutPut();

        //出力設定を元に戻す
        Console.SetOut( tmp );

        ////出力値をテスト
        bool result = writer.ToString().Equals( right );
        return result;
    }
}

この様にインタフェースを使用すると、親子関係がない多数のクラスのメソッドを、テスト出来るテストコードへ生まれ変わります。
 親クラスを指定していない点に注目して下さい。コンソールへ文字列を出力するクラスが親子関係を持つ事は、オブジェクト指向設計の観点から言って不自然なので、この場面ではインタフェースが適しています。特に多重継承が出来ない.NETでは、コンソールへ文字列を出力する為だけに、親クラスを定義して継承するのは得策ではありません。

class Piyo : IConsoleOut
{
    public void MessageOutPut()
    {
        Console.WriteLine( "おはピヨ♪" );
    }
}

class HelloWorld : IConsoleOut
{
    public void MessageOutPut()
    {
        Console.WriteLine( "Hello World!" );
    }
}

class Test
{
    static void Main( string[] args )
    {
        //テストの準備
        Tester tester = new Tester();

        //Piyoクラスのテストを実行
        Console.WriteLine("これからPiyoテストを実行します。");
        Piyo piyo = new Piyo();
        string right = "おはピヨ♪" + Environment.NewLine;
        bool result = tester.ConsoleOutCheck(
            ( IConsoleOut ) piyo,
            right );
        string message = result == true ? "テスト成功" : "テスト失敗";
        Console.WriteLine( message );
        Console.WriteLine();

        //HelloWorldクラスのテストを実行
        Console.WriteLine( "これからHelloWorldテストを実行します。" );
        HelloWorld hello = new HelloWorld();
        right = "Hello World!" + Environment.NewLine;
        result = tester.ConsoleOutCheck(
            ( IConsoleOut ) hello,
            right );
        message = result == true ? "テスト成功" : "テスト失敗";
        Console.WriteLine( message );
        Console.WriteLine();
    }
}

短いサンプルでは便利さが分かり難いかもしれませんが、長い文字列を処理結果に応じて出力するメソッドであっても、同様にテストできる点を考えると便利なテストコードだと言えます。
 しかしながら、このテストコードもまだまだ改善するべき余地があります。テストのためだけにインタフェースを実装するのは大変おかなしな事です。テスト対象はテストの事を考えず、適切なメソッドを定義できる様にするべきです。テストコードはテスト対象を変えるものではあってはなりません
 この問題点に対処する方法は・・・次回へ続く。

テーマ : プログラミング
ジャンル : コンピュータ

.NETテストプログラミング入門1

 この記事は、.NETテストプログラミング入門の続きです。前回から引き続き、コンソールへ文字列を出力するプログラムのテストを解説します。
 前回のサンプルコードを理解するには、コンソールが何をするものなのかを理解せねばなりません。System.ConsoleについてMSDNを調べると「コンソール アプリケーションの標準入力ストリーム、標準出力ストリーム、および標準エラーストリームを表します。」と書かれています。この文章を読むと、標準入出力ストリームについて知る必要がある事が分かります。
 各種標準ストリームの概念は古くからあり、私が知る限りでは初期のUNIXに存在していました。UNIXの設計思想は、小さいツールを組み合わせて使う事であり、個々のプログラムは単独で使用せず、組み合わせて使用するのが常識となっていました。それ故UNIXユーザ達は、UNIXパイプを使用し複数のプログラムを組み合わせて使っていました。
 UNIXパイプを使用する為に、各プログラムはデータのやり取りをせねばなりません。そこで、全てのデータをストリームとして考え、入出力およびエラーをストリームとして扱いました。ストリームとして扱う事の利点は、入力または出力先を柔軟に変更できる事です。この概念は非常に有効なものであり、今もなお使用されているので、標準入出力ストリームという言葉はプログラマ間で一般的に使用されています。
「標準」出力ストリームと言った場合、コンソールを指します。何故「標準」と付けるのかと言いますと、ストリームは柔軟に変更できるからです。コンソールへ出力するのを止め、メモリやファイルへ出力する事も可能です。ですから、コンソールクラスの説明に標準と書かれているのです。
 これを踏まえて、前回のテストコードを見れば意味が分かると思います。

//出力先を変えてテストを行いやすくする
TextWriter tmp = Console.Out;
StringWriter writer = new StringWriter();
Console.SetOut( writer );

 先ほど説明したように、出力ストリームは変更できます。そこで、テストが行いやすいように、メモリ上へデータを出力するように変更しています。これが出来れば後は簡単です。

//出力値をテスト
Piyo target = new Piyo();
target.Greeting();

//テスト結果を表示
string right = "おはピヨ♪" + Environment.NewLine;
bool result = writer.ToString().Equals( right );

 そして、上記コードでテスト対象となるPiyoクラスを実行し、メモリ上へ文字列を出力させ、その値を取得してチェックしています。なお、正しい文字列にEnvironment.NewLineを加算しているのは、Console.WriteLineメソッドは改行文字列が必ず付加されるからです。改行文字は忘れやすいので注意しましょう。
 このテストコードは一応作動しますが、テストコードとしては不十分なものです。テスト対象よりも多いコードを一々コーディングするのは時間の無駄です。テストコードも普通のコードなので、オブジェクト指向プログラミングの考えを適用し、再利用できるように改善せねばなりません。続く...

テーマ : プログラミング
ジャンル : コンピュータ

.NETテストプログラミング入門

 私はテストは特別なものではないと考えているので、本来「テストプログラミング」という言葉は使いたくありません。しかしながら、内容が伝わりやすいと思ったので敢えてこの題名にしました。この連載は、テストプログラムをプログラミングする方法と、テストの考え方を解説します。少しでもテスト時のお役にたてれば幸いです。
 プログラミングはコンソールへHello World等の文字列を表示する事から始まります。そこでこの連載もHello Worldに相当するコードのテストから始めます。
 ひとまず解答を掲載し、後で内容を解説します。

using System;
using System.IO;
class Piyo
{
    public void Greeting()
    {
        Console.WriteLine( "おはピヨ♪" );
    }
}

class Test
{
    static void Main( string[] args )
    {
        //出力先を変えてテストを行いやすくする
        TextWriter tmp = Console.Out;
        StringWriter writer = new StringWriter();
        Console.SetOut( writer );

        //テスト対象を実行
        Piyo target = new Piyo();
        target.Greeting();

        //出力値をテスト
        string right = "おはピヨ♪" + Environment.NewLine;
        bool result = writer.ToString().Equals( right );

        //テスト結果を表示
        Console.SetOut( tmp );
        string message = result == true ? "テスト成功" : "テスト失敗";
        Console.WriteLine( message );
    }
}

※通常はNUnitなどでチェックしますが、この連載では読みやすいようにコンソールへテスト結果を表示しています。

 テスト対象であるPiyoクラスは、文字列をコンソールへ出力する単純なコードです。こんな単純なプログラムは目視チェックすればよいと考えるかもしれませんが、如何に単純に思えるコードであっても、テストコードでチェックしなければなりません
 何故ならば、Hello Worldは極端な例ですが、単純なコードは実際のプロジェクトに多々存在するからです。また、「単純さ」は人によって異なります。新人は殆どのコードを難しく感じ、熟練者は殆どのコードが簡単だと感じるでしょう。その様ないい加減な感覚を尺度にして集団作業である開発はできません。
 単純なコードを放置すれば、コードカバレッジ(コード網羅率)が信用できなくなりますし、単純なコードを人間が一々目視でチェックするのは大変生産性が低い行為です。それに加え、「単純なコード」だからこそプログラマの集中力が途切れ、バグを埋め込む可能性があります。他にも理由は沢山ありますが長くなるので省略します。
 従って、人間に任せるのは得策ではありません。テストプログラムをプログラミングすれば、お手軽に高速かつ正確にコンピュータがチェックしてくれます。
 テストコードの内容については次回解説します。

テーマ : プログラミング
ジャンル : コンピュータ

プロフィール

インドリ

Author:インドリ
みなさん、はじめまして、
コンニチハ。

ボクは、無限の夢(infinity dream)を持つネタ好きな虹色の鳥インドリ(in dre)です。
色々な情報処理技術を啄ばむから楽しみにしてね。

http://twitter.com/indori
は別人による嫌がらせ行為です。
私とは関係ないので注意して下さい。
次はなりすましブログなどをするかもしれませんが、ここ以外でブログをするつもりがないので、ここ以外にインドリのブログがあったとしても無視してください。


何度言っても分からない人がいるので、ここにコメント欄へ書き込むときの注意事項を書きます。


一、社会人としてのマナーをわきまえましょう。
一、妄想に基づく書き込みを止めてください。
一、暴言の類は書かないで下さい。
一、某誹謗中傷サイトの書き込みは彼らの妄想に基づく書き込みですから無視して、ここへ書き込まないで下さい。
一、コメント書く前に他のコメントよく読んでから行って下さい。
一、言いがかかり等の行為を禁止します。
一、その他常識的に考えて迷惑なコメントはしないで下さい。


以上のルールを守れない人のコメントは削除します。



利用上の注意
ここに紹介してある文章およびプログラムコードは正確であるように心がけておりますが、内容を保証するものではありません。当サイトの内容によって生じた損害については、一切の責任を負いませんので御了承ください。


執筆したCodeZineの記事


【VB.NETで仮想CPUを作ろう】

  1. VB.NETで仮想CPUを作ろう
  2. レジスタの実装
  3. 仮想CPUのGUI化
  4. テストドライバの改良
  5. CPUの基礎動作の実装
  6. MOV命令の実装
  7. ADD命令実装
  8. SUB命令実装
  9. INC命令&DEC命令の実装と命令長
  10. MLU命令の実装とModR/Mについて
  11. DIV命令の実装とイベント設計について
  12. 機械語駆動式 関数電卓を作ろう!
  13. 機械語駆動式 関数電卓を作ろう! 解答編(前半)
  14. 機械語駆動式 関数電卓を作ろう! 解答編(後半)


【仮想ネットワーク実装でTCP/IPを学ぼう】
  1. TCP/IPの基礎と勘所
  2. ネットワークアクセス層の勘所
  3. インターネット層の勘所
  4. トランスポート層の勘所
  5. アプリケーション層の勘所
  6. セキュリティの基礎と仮想ネットワークの仕様
  7. GDI+と独自プロトコルの定義



【並列化】
インテル Parallel Studioを使って並列化プログラミングを試してみた
並列プログラミングの効率的なデバッグを実現する「Parallel Inspector」


【TBBシリーズ】
  1. インテル スレッディング・ビルディング・ブロックの概要
  2. インテルTBBから学ぶループの並列化
  3. スレッドセーフとインテルTBBのコンテナ
  4. インテルTBBのスレッドクラス


【OpenMPシリーズ】
  1. OpenMPの基礎構文
  2. OpenMPの実行時ライブラリと並列ループ
  3. OpenMPのメモリモデルとfork- joinモデル

最近の記事
最近のコメント
月別アーカイブ
カテゴリ
Ada (9)
COBOL (5)
C (9)
C++ (11)
C# (370)
D (25)
Java (8)
Perl (1)
Ruby (14)
PHP (2)
Boo (2)
Cobra (2)
LISP (6)
F# (33)
HTML (0)
XHTML (0)
CSS (0)
XML (0)
XSLT (0)
Scala (4)
WPF (0)
WF (2)
WCF (0)
LINQ (4)
MONO (5)
Linux (0)
MySQL (0)
ブログ内検索
リンク
最近のトラックバック
RSSフィード
ブロとも申請フォーム

この人とブロともになる

QRコード
FC2カウンター