redwarrior’s diary

C#, ASP.NET, WEB, G*などの雑多な情報

Angular 2をさわってみたので、参考になったサイトをまとめる。

とあるシステムを作り変えることになって、現在のシステムの解析や、システムの使われ方の聞き取りなどタスクが割り振られる中で、アーキテクチャの検証タスクになり、Webアプリによる実装の検証担当になり、Anugular2をさわってみたので、参考になったサイトなどをまとめる。

  • JavaScriptoon2

最初に読んだのがこれ。概要がわかりました。残念ながら、ソースはそのままでは動作しなくなっていました。いくつかのサイトを読んでみましたが、まだSystemJSを使用してローカルでの確認はできていません。

サイト

qiita.com

このサイトを見ながらやることで「Hello World」を動作させることができました。

hono-design.seesaa.net

わからないながらも、Angular2カテゴリを一通り読みました。

qiita.com

一通り目を通した後、ほかのサイトを読んでいて気になったところを何回か読み直しています。最初のサイトは、これの2日目の記事ですが、17日のDIに関する記事もおすすめです。

angular.io

公式のQuickstartです。ほかのサイトでQuickstart相当の内容は確認していますが、次に読むことになるTutorialの前提となっている内容なので、目を通しました。

angular.io

公式のチュートリアルです。今読んでいるところです。

plnkr.co

公式などからリンクされているブラウザ上で動作確認ができるサイトです。アップデートなどでローカルだとビルドや実行がうまくいかないことがあるので、このサイト上で動作を確認しながら学んでいます。

Angular2 Info

開発状況や更新情報を日本語でまとめてくれているサイトです。公式のQuickstart通りにやってもうまくいかない時は、ここを参照すると良いと思います。

とりあえず、こんなところ。

(小ネタ)2重ループをLINQを使って書く

コレクションが二つあって、片方のコレクションの値で、もう片方のコレクションを検索して処理を行う時に、2重ループを使うことがありますが、これはLINQを使用して書くことも出来ます。

C#で解説する「データ処理の直交化と汎用化」 − @IT

ただしサイト内で言われているように、LINQメソッド構文で行う場合はSelectManyメソッドを使用するのですが、使い方と理解するのがなかなか難しい。

クエリ式を使用すると、このケースにおいては、SQLを知っていればだいぶ理解しやすくなるのでクエリ式を使用するのが良いようです。


ちなみに、片方のコレクションに含まれているインスタンスに、もう片方のコレクションのインスタンスの値を代入する場合は、以下のようにforeach文を使用した方が楽な気がします。

foreach (var obj in listB)
{
    var single = listA.SingleOrDefault(o => o.Id == obj.Id);

    if (single == null)
    {
        continue;
    }

    single.prop1 = obj.prop1;
    single.prop2 = obj.prop2;
}

(小ネタ)改行文字を削除する

ささいな事ですが、うっかり引っかかったのでまとめておきます。

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でも動作します。

参考サイト

文字列内の改行文字を削除するには?[C#、VB] − @IT

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を使用する。

  • asyncなメソッドは、メソッド呼び出すと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年前のブログでした。ただ自分が知ったのは最近で、結構ためになったので書くことにしました。

開発環境:

Windows 8.1

VisualStudio 2015 Professional

ASP.NET MVC(or Web API) 5.2.3

Entity Framework 6.1.3

MSTest

参考サイト

接続文字列に"|DataDirectory|"を使用したMSTestプロジェクトでやっとくこと - なか日記

Visual Studio 2015は、Professionalでもユニットテスト機能(MSTest)が充実している

Visual Studio 2015になって、Professionalエディションでもユニットテストが便利になったと実感したので忘れずに書いておく。

便利だと思ったのは以下の2つ。

  • テスト対象クラスのメソッドから、テストクラス/メソッドを作成する
  • テスト対象クラスのメソッドから、テストクラス/メソッドに移動する

テスト対象クラスのメソッドから、テストクラス/メソッドを作成する

テスト対象クラスを開いて、右クリックから「単体テストの作成」を実行すると、
以下の画面が表示されて、必要な値を入力してOKをクリックするとテストプロジェクト/クラス/メソッドを作成してくれる。

f:id:redwarrior:20151205165758p:plain

2つほど注意点があって、1つは名前空間の問題。作成画面ではテスト対象クラスの名前空間を[Namespace]という変数で表現している。
しかし、Visual Studioのテンプレートでテストプロジェクトを作成していると、名前空間に「.Tests」が含まれてしまうので、フォルダを分けていた場合(例えばControllerフォルダに作成していた場合)に以下の差が発生する。

  • 手動で作成したテストの名前空間  → プロジェクト名.Tests.Controller
  • 画面から作成したテストの名前空間 → プロジェクト名.Controller.Tests

これを避けるために、テストプロジェクトのプロパティ画面を開いて名前空間から「.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」をやってみても良いと思います。