(小ネタ)改行文字を削除する
ささいな事ですが、うっかり引っかかったのでまとめておきます。
C#で文字列に含まれている改行文字を取り除く方法は、改行文字を含む位置によって違います。
- 末尾にある場合
TrimEndメソッドに改行文字を渡します。環境に依存しないようにCRとLFを両方とも渡します。
string m = "あいうえお\n"; m.TrimEnd('\r', '\n'));
- 先頭にある場合
TrimStartメソッドに改行文字を渡します。こちらを使うことはあまり無いと思います。
string m = "\nかきくけこ"; m.TrimStart('\r', '\n'));
先頭と末尾の両方を対象とするTrimメソッドというものもあります。
- 文中にある場合
文中に改行文字がある場合は、Trim***メソッドでは処理されません。ここに引っかかってしまいました。
この場合は、Replaceメソッドを使用します。注意点としては改行文字は、ダブルクォートで囲むことです。
string m = "さしすせそ\nたちつてと"; m.Replace("\r", "").Replace("\n", "");
上記の例では、文字列に含めた改行文字には \n を使用しましたが、\r でも \r\n でも、Environment.NewLineでも動作します。
参考サイト
awaitは、中断と再開
前回からだいぶ時間が空いてしまいました。本年もよろしくお願いいたします。
C# 5.0以降で可能になったasyncとawaitとTaskについての自分用のメモ。ASP.NET MVCやWeb APIでは必要になってくる知識。
ググった結果を斜め読みしてまとめたメモなので、awaitの前後で別スレッドで動作するか検証したとかではないです。
参考サイトのURLをメモしてないので、上記についてまとめられたサイトがあれば教えてくれるとうれしいです。
awaitは、中断と再開。
awaitが処理された時点で、以降(の行)の処理が中断されて呼び出し元へ移動する。
Waitする箇所(WaitXXメソッドを呼ぶ等)を作らなければ、中断は呼び出し元へと波及していく。
awaitは、async修飾子のついたメソッドで使用可能。
asyncは、中でawaitを使用していないメソッドにもつけることが可能だが、非同期では無いメソッドではつける意味があ まりない。
ayncなメソッドの返却値は、Taskもしくはvoidでなければならない。voidは非推奨っぽいのでTaskを使用する。
awaitは、asyncなメソッドの戻り値であるTaskクラスを処理する。
awaitを使用する代わりに、TaskクラスのWaitXXメソッドを呼ぶことが出来る。
Taskが戻って来た時点でayncなメソッド処理は行われているため、asyncなメソッドの呼び出しとawaitの使用を分けることで、「メソッドの実行」と「結果の取得」を分けることが出来る。
テストプロジェクトからメインプロジェクトのDBを参照する
この記事は Windows & Microsoft技術 基礎 Advent Calendar 2015 - Qiita の15日目です。
アドベントカレンダーからいらした方、初めまして。今年の始めのあたりからブログを書き始めた redwarriror と申します。
普段はC#等のMicrosoft系の技術を中心に書いています。今回の内容も他のアドベントカレンダーに書いた方が良い内容なのかもしれませんが、参加するかどうか&テーマに悩んでいる間に埋まってしまいました(苦笑)。いざテーマを決めた後、このアドベントカレンダーが丁度空いていたので、思い切って参加してみました。
さて、さっそくですが、ASP.NET MVC/Web APIで、DBに接続してデータを取得するプログラムのテストってどうやっていますか?
自分はテンプレートからプロジェクトを新規作成するときに、テストプロジェクトも一緒に作成するようにしてます。
そうするとテストプロジェクトが別に用意されて設定ファイルも別になります。この状態でテストクラスからどうやって上記プログラムのテストをするかという話です。
検討
いろんな方法が考えられます。
- モックオブジェクトを使用する
- テストプロジェクトにもDBを用意する
- ローカルのDBを使用しない
- テストプロジェクトを作成しない。
モックオブジェクトを使用する
良いアイデアだと思います。大部分はこれでまかなえると思います。ライブラリとしては、自分はMoqをよく使います。ただし、これだとDBに接続できるかというテストは出来ませんし、モックオブジェクトの設定が大量・複雑になりやすいです。
テストプロジェクトにもDBを用意する
開発中はLocalDBをよく使用するので準備はこれが簡単かもしれません。ただし、DBが2か所にあるということで、マスタ系の初期データの投入プログラムが2か所に重複しますし、マイグレーションの時に困ります。
ローカルのDBを使用しない
LocalDBを使用せずDBサーバーを建てるのも一つの手です。ただし、DBが共有の場合は他への影響が気になってデータの追加・削除がやりづらいですし、ローカルのDBサーバーをインストールする権限がないかもしれません。
テストプロジェクトを作成しない。
メインプロジェクトにテストクラスを作成する方法です。Microsoftの流儀に沿っていない気がするので、若干の不安と気持ち悪さがあります。あと、ビルドやデプロイ時にテストクラスやテスト用ライブラリを除外する方法を知らないと、テストコードも含んだ実行ファイルが作成されてしまいます。
結局
やりたい事はテストプロジェクトからメインプロジェクトのDBにアクセスしたいだけなんだから、もっと良い方法があるはずだと思って、ネットサーフィンをし続けた結果、DataDirectoryの値を変更するという方法にたどり着きました。(参考サイト)
やり方
やり方としては、まずテストプロジェクトにEntity Frameworkをインストールします。次にメインプロジェクトのWeb.configのconnectionStringsの値を、テストプロジェクトのApp.configにコピーします。
<connectionStrings> <add name="TestContext" connectionString="Data Source=(localdb)\v11.0; Initial Catalog=TestContext-20150902120557; Integrated Security=True; MultipleActiveResultSets=True; AttachDbFilename=|DataDirectory|TestContext-20150902120557.mdf" providerName="System.Data.SqlClient" /> </connectionStrings>
そうしたら以下のクラスを DataDirectoryInitialize.cs という名前でテストプロジェクトに作成します。クラスの作成場所はどこでも良いみたいなので、DALフォルダを作成してその下に置きました。
public class DataDirectoryInitialize { [AssemblyInitialize] public static void AssemblyInitialize(TestContext context) { var directory = AppDomain.CurrentDomain.BaseDirectory; var replace = directory.Replace(@".Tests\bin\Debug", string.Empty); var combine = Path.Combine(replace, "App_Data"); AppDomain.CurrentDomain.SetData("DataDirectory", combine); } }
上記ではテストプロジェクトの命名ルールを活かして、メインプロジェクトのApp_Dataフォルダ(メインプロジェクトのDataDirectoryの場所)を指定するように設定しています。
これでTestContextをnewした時に、メインプロジェクトのDBに接続することが出来ます。また、IDatabaseInitializerを継承したクラスによる初期データ投入も行われます。
あとはテストメソッドの中で、以下のようにTransactionScopeを使用すれば、テストごとに自由にDBを触ることが出来て、後始末もしてくれます。
[TestMethod] public void ConnectionTest() { using (TransactionScope transactionScope = new TransactionScope()) //終了時にロールバック { using (TestContext context = new TestContext()) //メインProjectのデータベースを取得 { // Usersテーブルの初期化,他のテーブルは残す context.Users.RemoveRange(context.Users); context.SaveChanges(); // テストデータの追加、テストの実施などを記述する ... } } }
以上です。
ちなみに参考にしたのは昨年書かれたブログ(参考サイト)ですが、そこから参照されているのはさらに7年前のブログでした。ただ自分が知ったのは最近で、結構ためになったので書くことにしました。
開発環境:
VisualStudio 2015 Professional
ASP.NET MVC(or Web API) 5.2.3
Entity Framework 6.1.3
MSTest
参考サイト
Visual Studio 2015は、Professionalでもユニットテスト機能(MSTest)が充実している
Visual Studio 2015になって、Professionalエディションでもユニットテストが便利になったと実感したので忘れずに書いておく。
便利だと思ったのは以下の2つ。
- テスト対象クラスのメソッドから、テストクラス/メソッドを作成する
- テスト対象クラスのメソッドから、テストクラス/メソッドに移動する
テスト対象クラスのメソッドから、テストクラス/メソッドを作成する
テスト対象クラスを開いて、右クリックから「単体テストの作成」を実行すると、
以下の画面が表示されて、必要な値を入力してOKをクリックするとテストプロジェクト/クラス/メソッドを作成してくれる。
2つほど注意点があって、1つは名前空間の問題。作成画面ではテスト対象クラスの名前空間を[Namespace]という変数で表現している。
しかし、Visual Studioのテンプレートでテストプロジェクトを作成していると、名前空間に「.Tests」が含まれてしまうので、フォルダを分けていた場合(例えばControllerフォルダに作成していた場合)に以下の差が発生する。
これを避けるために、テストプロジェクトのプロパティ画面を開いて名前空間から「.Tests」を削除して、作成画面の名前空間の指定からも「.Tests」を削除するようにしている。前回の設定が保存されるので次回から設定する必要はない。
もう1つの注意点は、作成対象がpublicメソッドのみというところ。public以外のメソッドはいちいち修飾子を変更するのが若干面倒。
テスト対象クラスのメソッドから、テストクラス/メソッドに移動する
こちらはいたってシンプル。CodeLensにテスト用の表示が追加されているので、それをクリックすれば移動できる。ショートカットキー「Alt+3」でも可能。
これでガンガンテストをしていきたい。
確認環境: Windows 8.1 Pro Visual Studio 2015 Professional
(小ネタ)EqualsメソッドもGetHashCodeメソッドもReSharperで!
ReSharperカテゴリの2つ前と操作がほとんど一緒ですが、機能紹介ということで。
csファイル(クラス)を開いて、メニューのRESHARPER→Edit→Generate Codeと選択し(もしくはクラス内にカーソルを合わせて「Alt」を押しながら「Insert」を押す)、
出てきたメニューから「Equality members」を選択すると、プロパティを選択する画面が出てくるので、メソッドに含んでほしいプロパティを選択して、Finishボタンをクリックすると作成してくれます。
チェックボックスで細かい挙動を変えることが出来ますフォルトのままで良いと思います
Fields can be null: フィールドにnullを設定できるかどうか、GetHashCodeメソッドの中身が変わります。
Overload equality operators: ==演算子の動作を変更するかどうか。
Implement IEquatable
interface: IEquatable インターフェースを実装するかどうか。 Comparand type check: 選択肢が3つあるんですが、1つ目と2つ目の違いが良く分かりません。いずれにしろ継承をしていなければ関係ないようです。
すばらしい!
上記以外にもまだまだ機能があるので、クラスを作成したら「Alt+Insert」をやってみても良いと思います。
(小ネタ)C#のユニットテストで public でないメソッドをテストする方法(MSTest)
Javaでは、publicでないメソッド(かつ、privateでもない)をテストする場合は、packageを一緒にすれば良かったのですが、C#ではどうやるんだろうと思って調べました。
参照先の通りにやったら出来たので、特に追記することはありません。
ソースコード単位で設定する方法
プロジェクト単位で設定する方法
Visual Studio の単体テストで利用するInternalsVisibleTo属性について | もりひろゆきの日々是勉強
アセンブリ署名がされている場合
ちなみに、privateメソッドはこの方法でもテストできません。この場合は、リフレクションを使うのでしょう。
(小ネタ)C#でメソッドの引数に値渡しが行われるのは、値型のみ
自作クラスなどの参照型の引数に ref とか out とかつけるのは意味がなく、m9(^Д^)プギャーされるのでやめた方が良いですね。
自作の構造体や列挙型は値型なので、参照渡しが必要ならばつけましょう。