2023/03/23(木)Visual Studio 2022 Communityで手軽にC#.NETのコードカバレッジを見る方法
投稿日:
TypeScriptやJavaScriptだとコマンド一発で見れるコードカバレッジだが、C#.NETの開発ではちょっと手こずったので導入方法を記録しておく。
確認環境
| Env | Ver |
|---|---|
| Visual Studio 2022 Community | Version 17.5.1 |
| .NET Framework | 6.0 |
導入手順
- C#.NETで開発用のプロジェクトを作成
- 作成したプロジェクトのソリューションにxUnitテストプロジェクトを追加
- 何かしらの実装と、それに対するテスト実装を作成
- Fine Code CoverageをVisual Studioにインストール
- ソリューションエクスプローラからxUnitテストプロジェクトを右クリックしてテストの実行
- 下部トレイにあるFine Code Coverageタブを選択
- コードカバレッジが表示される
疑問
Visual Studio 2022にもなって標準でコードカバレッジも取れないの?
今どきそんな事あるか?思って調べてみたところ、どうやらEnterpriseであればコードカバレッジを取る機能がついている模様。
まぁ無料版だから仕方ないねということで諦めるしかないでしょう。Professional版にもないけど…w。VisualStudioの便利機能は以前から有料機能に組み込まれる傾向があるので仕方がない気もしますが、取り敢えず今回は有志が便利なツールを作っていてくれて助かりました。
因みにコードカバレッジ自体は無料版でも取れます。ただこれはXMLのカバレッジレポートを吐くだけなので、可視化するには別途ここからHTMLを生成する必要があり面倒なので、なんかもっと楽な方法はないかなと思って見つけたのが今回のFine Code Coverageでした。
しかしFine Code Coverage便利なのにそこまで利用されているように見えないのは、やはりテストに関心がある人が少ないのか、公式にあるカバレッジHTMLを吐く方法で納得しているのか、その辺りが気になりました。自前でFine Code Coverageの様な物を作っている人もいるでしょうが、それは少数派だと思いますし。
この方法で取れるカバレッジは正しいものか?
GitHubのREADMEを読む限り、組み込みのカバレッジレポーターのAPIを叩いて取ってきたものを表示しているだけに見えるので、恐らく正しいデータが出ているのではないかと思います。
少なくとも単純なコードのUnit testingを書いた感じではテストケースを増減することでカバレッジも連動して増減していたのと、組み込みのレポーターがそのくらいはやってくれている筈で、これはその内容を表示しているだけなので恐らく大丈夫なのではないかと考えています。
2021/03/12(金)Rx.NETでWindows Formを操作するサンプル
投稿日:
System.ReactiveをNuGetから入れるthis.ticker= Observable.Interval(new TimeSpan(0, 0, 15));でObserverを作る
this.ticker.Subscribe(
(item) => {
// 任意のコントロールを操作する例
// this.Invokeでコントロールを操作するメソッドを呼び出すと実現できる
this.Invoke(
(MethodInvoker)(delegate () {
// ここに処理
})
);
}
);
どうでもいいけどRx.NETってちゃんとしたリファレンスなくね?
2019/10/06(日)C#.NETのDataTableをLINQで操作する
投稿日:
なぜこんな実装が必要なのかさっぱり不明ですが、必要になって困ったのでメモ。
DataTableを内部結合したList<Dictionary>をLINQで作る
var loc = new DataTable();
var pep = new DataTable();
loc.Columns.Add("ID");
loc.Columns.Add("LOCATION");
loc.Columns.Add("DELETE_FLG");
loc.Rows.Add("100", "US", "0");
loc.Rows.Add("101", "AU", "1");
loc.Rows.Add("102", "JP", "1");
loc.Rows.Add("103", "CH", "1");
loc.Rows.Add("104", "UK", "1");
loc.Rows.Add("105", "RU", "1");
pep.Columns.Add("LOCATION_ID");
pep.Columns.Add("NAME");
pep.Columns.Add("DELETE_FLG");
pep.Rows.Add("100", "TAKANA", "0");
pep.Rows.Add("101", "YAKATA", "1");
pep.Rows.Add("100", "WADA", "1");
pep.Rows.Add("101", "SHINODA", "1");
pep.Rows.Add("100", "HARUKA", "1");
pep.Rows.Add("105", "SAIONJI", "0");
var result = (
from l in loc.AsEnumerable()
join p in pep.AsEnumerable()
on new {
a = l.Field<string>("ID"),
b = l.Field<string>("DELETE_FLG")
} equals new {
a = p.Field<string>("LOCATION_ID"),
b = p.Field<string>("DELETE_FLG")
}
select new Dictionary<string, string> {
{
"LOCATION_ID",
l.Field<string>("ID")
},
{
"NAME",
p.Field<string>("NAME")
}
}
).ToList();
List<Dictionary>とDataTableを外部結合してList<Dictionary>を操作する
var location = new List<Dictionary<string, string>>();
var fruits = new DataTable();
location.Add(
new Dictionary<string, string> {
{
"ID",
"001"
},
{
"NAME",
"Hokkaido"
}
}
);
location.Add(
new Dictionary<string, string> {
{
"ID",
"002"
},
{
"NAME",
"Aomori"
}
}
);
location.Add(
new Dictionary<string, string> {
{
"ID",
"003"
},
{
"NAME",
"Iwate"
}
}
);
fruits.Columns.Add("LOCATION_ID");
fruits.Columns.Add("NAME");
fruits.Columns.Add("FRUITS_FLG");
fruits.Rows.Add("001", "ikura", "1");
fruits.Rows.Add("001", "uni", "1");
fruits.Rows.Add("002", "ringo", "0");
// dummyは処置待ち用のダミー。locationの操作が目的
var dummy = location
.Join(
fruits.AsEnumerable()
, loc => loc["ID"]
, fruit => fruit.Field<string>("LOCATION_ID")
, (loc, fruit) => new { lo = loc, fru = fruit }
)
.Select(
joined => {
joined.lo["FRUITS_NAME"] = joined.fru.Field<string>("NAME");
joined.lo["FRUITS_FLG"] = joined.fru.Field<string>("FRUITS_FLG");
return new Dictionary<string, string>();
}
)
.ToList();




