.NETツールを使用した単体テスト

ユニット(またはユニット、別名)テストの主なアイデアは、個々のプログラムコンポーネントのテストです。 クラスとそのメソッド。 テストで覆われたコードを開発すると非常に便利です。正しく使用すると、プログラムの開発履歴の回帰の可能性が実質的に排除されます。 TDD開発方法論であるテスト駆動開発も、現在非常に流行しています。 彼女によると、プログラマーは最初に将来の機能のために一連のテストを開発し、実行するためのすべてのオプションを計算してから、すでに書かれたテストに適した直接動作するコードを書き始めます。



プログラムにテストが存在することは、開発者の資格を確認するだけでなく、多くの場合顧客の要件でもあるため、この問題に取り組み、テストに「触れる」ことにしました。



私は主にVisual Studioで仕事をしていますが、sharpeで書いています。つまり、選択はほとんど2つの製品(NunitとUnit Testing Framework)に限定されていました。



単体テストフレームワークは、Microsoftが開発したVisual Studioに組み込まれたテストシステムであり、常に進化しています(最新の更新プログラムの中には、既にHabréで記述されたUIをテストする機能があります)。最も重要なことは、Visualスタジオ、サードパーティの開発について言うことはできません。 IDEの優れた統合と、プログラムのコードカバレッジの割合を計算する機能が最終的にスケールを決定しました-選択が行われました。

ネットワークには、かなり多数のさまざまなテストチュートリアルが含まれていますが、通常はすべて、記述された計算機のテストまたは文字列の比較になります。 もちろん、これらのことも必要であり重要ですが、深刻な例を引き出していません。率直に言って、そうではありません。 私自身も、頭の中でそのようなタスクをテストできます。



ここに、より深刻なタスクのリストがあります

•データベース作成の正確性の確認

•ビジネスロジックの検証

•このすべての恩恵(私の場合、恩恵を受けました)



それでは始めましょう!



DBテスト


テストと健全なロジックの原則に従って、テスト用の別のベースを用意します。 したがって、TestDBデータベースを作成し、Usersテーブルを追加します

CREATE TABLE [dbo].[Users](

[id] [ int ] IDENTITY (1,1) NOT NULL ,

[login] [ nchar ](100) COLLATE Ukrainian_CI_AS NOT NULL ,

[hash] [ nchar ](50) COLLATE Ukrainian_CI_AS NOT NULL ,

[ level ] [ int ] NULL ,

CONSTRAINT [PK_Users] PRIMARY KEY CLUSTERED

([id] ASC )

WITH (PAD_INDEX = OFF , STATISTICS_NORECOMPUTE = OFF , IGNORE_DUP_KEY = OFF , ALLOW_ROW_LOCKS = ON , ALLOW_PAGE_LOCKS = ON ))

CREATE UNIQUE NONCLUSTERED INDEX [IX_UserName] ON [dbo].[Users]

([Login] ASC )

WITH (PAD_INDEX = OFF , STATISTICS_NORECOMPUTE = OFF , SORT_IN_TEMPDB = OFF , IGNORE_DUP_KEY = OFF , DROP_EXISTING = OFF , ONLINE = OFF , ALLOW_ROW_LOCKS = ON , ALLOW_PAGE_LOCKS = ON )









データを入力します

INSERT [dbo].[Users] ([Login], [Hash], [ Level ]) VALUES (N 'Sirix' , N '827ccb0eea8a706c4c34a16891f84e7b' , 1)

INSERT [dbo].[Users] ([Login], [Hash], [ Level ]) VALUES (N 'Tester' , N '3095C3E4F1465133E5E6BE134EB2EBE2' , 1)

INSERT [dbo].[Users] ([Login], [Hash], [ Level ]) VALUES (N 'Admin' , N 'E3AFED0047B08059D0FADA10F400C1E5' , 2)

INSERT [dbo].[Users] ([Login], [Hash], [ Level ]) VALUES (N 'U1' , N '827CCB0EEA8A706C4C34A16891F84E7B' , 1)







テストするストアドプロシージャを追加します。 彼女は、なじみのあること-特定のログインおよびパスワードハッシュのユーザーIDを返すことに従事します。

CREATE PROCEDURE [dbo].[GetUserId]

(

@login nchar (100),

@hash nchar (50),

@id int OUTPUT

)

AS

SELECT @id = ID FROM Users WHERE Login = @login AND hash = @hash

RETURN







*このソースコードは、 ソースコードハイライターで強調表示されました。



単体テストフレームワークを使用すると、スキーマ、テーブル内のレコード数、ストアドプロシージャ、クエリ実行時間、それらの結果など、データベースのさまざまな側面をテストできます。



テストを開始する


TestProjectのような新しいソリューションを作成します。 LinkCatalog.Testsと呼びましょう。 そして、新しいデータベースユニットテストを追加します。



データベース接続を設定するためのウィンドウが表示されます。 データベースへの接続を設定し、[OK]をクリックします。 同じウィンドウで、テストのデータ自動生成パラメーターを指定できます。 この関数はデータ生成プランを使用し、パターンや正規表現を使用して、データベーステーブルにテスト値を入力できます。

[OK]をクリックして、データベースのテストウィンドウに移動します。



テスト番号1


最初のテストが最も簡単です。 テーブルのエントリ数を確認します。

Select count (*) FROM Users







次に、テストが正しい条件を確立します。 前述したように、すべての種類の基準の大きなリストがありますが、最も単純なものの1つであるScalarValueに興味があります。



すべての条件オプションは、[プロパティ]ウィンドウで構成されます。





それだけです! 最初のテストが完了しました。 実行して見る



必要に応じて、文字列はデータベースに正常に保存されます。



テスト番号2


レコードの数よりも実際のチェックを行うときが来ました。 これはストアドプロシージャです。 データベースの開発者が重大な間違いを犯した場合はどうなりますか? しかし、これはユーザー認証サブシステムの最も重要な部分です!

緑色のプラス記号をクリックして、新しいデータベーステストを作成します。







テストコードは次のとおりです。

/* */

DECLARE @id INT ;

SET @id = -1



/* id = 1 */

EXEC GetUserId N 'Sirix' , N '827ccb0eea8a706c4c34a16891f84e7b' , @id OUTPUT ;



SELECT * FROM Users WHERE id = @id




* This source code was highlighted with Source Code Highlighter .






ここでは別の条件がすでに使用されています-選択範囲には正確に1つの行があることが予想されます。





このテストも成功します。これは朗報です。



データベースのテスト結果によると、データベースは安定しており、期待どおりに機能していると言えます。 これで、データベースプロシージャのカバレッジは100%に達しました。これは、より複雑なアプリケーションや、より多くのテーブル/プロシージャ/リレーションシップを持つデータベースでは簡単に達成できない制限です。



コードユニットテスト


それでは、コードのテストを始めましょう。

MVCパターンを実装した小さなASP.NETアプリケーションがありました。 モデルは、DALという名の独立したアセンブリであり、データベースにアクセスするためのラッパーが含まれていました。 要件の1つは、ADO.NETでDataReaderを使用することでした。 通常の設定はweb.configに保存されます。

モデルのテストを開始することにしました。このコードはテストするものでした

namespace LinkCatalog.DAL

{

public class UserModel

{

...........

public static int GetUserIdByName(string username)

{

string query = " SELECT ID FROM Users WHERE Login = @login;";

DB. get ().CommandParameters. Add ( new SqlParameter("@login", username));



int id = -1;



int .TryParse(DB. get ().GetOneCell(query).ToString(), out id);



return id;

}

}

public class DB

{

...........

private static DB instance;



public static DB get ()

{

if (instance == null )

instance = new DB();



return instance;

}



private SqlConnection connection ;

private SqlDataReader reader;



public List CommandParameters;

private DB()

{

this. connection = new SqlConnection(WebConfigurationManager.ConnectionStrings["DBConnectionString"].ConnectionString);

this.CommandParameters = new List();

}



public object GetOneCell(string query)

{

SqlCommand sc = new SqlCommand(query, this. connection );



if (this.CommandParameters. Count != 0)

sc. Parameters .AddRange(this.CommandParameters.ToArray());



this. connection . Open ();



object res = sc.ExecuteScalar();

this.CommandParameters.Clear();



this. Close ();

return res;

}

}

}



* This source code was highlighted with Source Code Highlighter .






プロジェクトに新しい単体テストを追加する



このコンテンツのファイルを取得します。

using System;

using System.Text;

using System.Collections.Generic;

using System.Linq;

using Microsoft.VisualStudio.TestTools.UnitTesting;



namespace LinkCatalog.Tests

{

[TestClass]

public class UserModel_Tests

{

[TestMethod]

public void TestMethod1()

{

}

}

}



* This source code was highlighted with Source Code Highlighter .






[TestClass]属性は、このクラスにテストメソッドが含まれることを意味し、[TestMethod]はそのようなメソッドが特定のメソッドであることを意味します。

プロジェクトのDALアセンブリへのリンクを追加し、LinkCatalog.DAL名前空間をインポートします。 準備作業が完了したら、テストを作成します。

using Microsoft.VisualStudio.TestTools.UnitTesting;



namespace LinkCatalog.Tests

{

using LinkCatalog.DAL;

[TestClass]

public class UserModel_Tests

{

[TestMethod]

public void GetUserById_Test()

{

Assert.AreNotEqual(UserModel.GetUserIdByName(" Admin "), -1);

}

}

}




* This source code was highlighted with Source Code Highlighter .






このログインには常に管理者がいるため、彼の識別子を-1にすることはできません。

テストを実行します-エラー:



例外がポップアップしました:

Test method LinkCatalog.Tests.UserModel_Tests.GetUserById_Test threw exception:

System.NullReferenceException: Object reference not set to an instance of an object .

LinkCatalog.DAL.DB..ctor() in C:\Users\\Documents\Visual Studio 2010\Projects\Practice\DAL\Database.cs: line 35

LinkCatalog.DAL.DB. get () in C:\Users\\Documents\Visual Studio 2010\Projects\Practice\DAL\Database.cs: line 17

LinkCatalog.DAL.UserModel.GetUserIdByName( String username) in C:\Users\\Documents\Visual Studio 2010\Projects\Practice\DAL\Models\UserModel.cs: line 63

LinkCatalog.Tests.UserModel_Tests.GetUserById_Test() in C:\Users\\Documents\Visual Studio 2010\Projects\Practice\LinkCatalog.Tests\UserModel_Tests.cs: line 12




* This source code was highlighted with Source Code Highlighter .






ご覧のとおり、エラーはDBクラスのコンストラクターにあります。構成ファイルが見つからないため、テストが失敗するだけでなく、エラーも発生します。



構成ファイルの問題の解決策は非常に簡単です。

いいえ、テスト環境はweb.configを自動的に接続しません。 代わりに、各テストプロジェクトは独自のapp.config構成ファイルを作成し、必要なことは必要な設定を追加することだけです。

<? xml version ="1.0" encoding ="utf-8" ? >

< configuration >



< configSections >

< section name ="DatabaseUnitTesting" type ="Microsoft.Data.Schema.UnitTesting.Configuration.DatabaseUnitTestingSection, Microsoft.Data.Schema.UnitTesting, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />

</ configSections >

< DatabaseUnitTesting >

< DataGeneration ClearDatabase ="true" />

< ExecutionContext Provider ="System.Data.SqlClient" ConnectionString ="Data Source=SIRIXPC\sqlexpress;Initial Catalog=TestDB;Integrated Security=True;Pooling=False"

CommandTimeout ="30" />

< PrivilegedContext Provider ="System.Data.SqlClient" ConnectionString ="Data Source=SIRIXPC\sqlexpress;Initial Catalog=TestDB;Integrated Security=True;Pooling=False"

CommandTimeout ="30" />

</ DatabaseUnitTesting >





< connectionStrings >

< add name ="DBConnectionString" connectionString ="Data Source=SIRIXPC\SQLEXPRESS;Initial Catalog=tbd;Integrated Security=True"

providerName ="System.Data.SqlClient" />

</ connectionStrings >



</ configuration >




* This source code was highlighted with Source Code Highlighter .







これでテストが成功しました:



テストを少し変えましょう

[TestMethod]

public void GetUserById_Test()

{

Assert.AreNotEqual(UserModel.GetUserIdByName( "Admin" ), -1);



Assert.AreEqual(UserModel.GetUserIdByName( "0-934723 ### 12sdf s" ), -1);

}




* This source code was highlighted with Source Code Highlighter .






データベースでのそのようなログインの保証はありません(ログインにはスペースを入れないでください。登録中にコントローラーのバリデーターが続きます)。これはメソッドの2番目と最後のテストです。



テストは再び失敗します-詳細を確認します:

Test method LinkCatalog.Tests.UserModel_Tests.GetUserById_Test threw exception:

System.NullReferenceException: Object reference not set to an instance of an object .



UserModel.GetUserIdByName, null :

int .TryParse(DB. get ().GetOneCell(query).ToString(), out id);

:

var res = DB. get ().GetOneCell(query);

if (res != null )

int .TryParse(res.ToString(), out id);




* This source code was highlighted with Source Code Highlighter .








これですべてがOKです!



これは、忘れがち/怠iness /知識ではなくても、テストがプログラムのエラーを特定するのに役立ちますが、ライブサーバーよりもこの方法で修正する方が簡単です。 もちろん、このトピックはテストプログラムのすべての側面を網羅しているわけではなく、この領域のみを公開しています。 背後には、他のテスト、ユーザーインターフェイステストなどに依存する条件付きテストの可能性がありました。



プログラムをテストし、バグはほとんどありませんが、多くの機能があります!



All Articles