単体テスト<C#> async な moq をセットアップするときにハマったこと
C# で単体テストで moq を使用した場合のお話です。
備忘録として残しておきます。
以下のようなインターフェイスがあったとします。
public interface IHoge { Task SomethingAsync(int x); }
これを moq
でセットアップする場合、以下のように書く必要があります。
Mock<IHoge> hogeMock= new Mock<IHoge>(); hogeMock.Setup(m => m.SomethingAsync(It.IsAny<int>())).Callback<int>((value) => { // Assert.Equal 等の何かしらの処理をここに記述 }).Returns(Task.CompletedTask);
重要なのが .Returns(Task.CompletedTask)
の部分で、 Task async
で実装されるメソッドにはこれをセットアップする必要があります。
でないと、メソッドをコールしても NullReferenceException
の例外が投げられてしまいます。
なんとも不親切な例外なので、かなりハマりました・・・
C言語の JSON シリアライザー parson について
parson の紹介
C言語で JSON をシリアライズすることができないか探していると、 parson
なるものを見つけました。
速度はわかりませんが、特徴としては以下のようです。
下記の参考ページに、サンプルなどが載っているので参考になります。
↓文字列を使用することなくパースする、実践的なやり方が公開されています。
かなり参考になります。
↓サンプルを公開されているサイト
↓公式サイトです。
シリアライズとデシリアライズのサンプルがあります。
<おまけ>言語別 JSON parser 一覧
ちなみに、C言語で JSON をシリアライズ/デシリアライズするのは結構あるみたいです。(こちら参照)
特に気になるのを列挙しておきます。
cJSON
jansson
npm で fatal: unable to connect to github.com: と怒られるとき
npm
コマンドを使ってインストールを行うとき、fatal: unable to connect to github.com:
と怒られました。
その解決方法です。
条件
ファイアウォールの問題らしいです。
恐らく社内等のネットワーク環境とかが考えられます。
対策
以下を実行します。
git config --global url."https://".insteadOf git://
要は、git://~
というプロトコルがダメらしく、それならば http://~
でアクセスしてやる、というやり方みたいです。
参照
今回、 gitbook のインストールを試していて、gitbbok-plugin-uml
をインストールしようとしたら上記症状が発生しました。
ProtocolBuffers の C# 版の Timestamp について
前に ProtocolBuffers の C# 版の導入をやってみたのですが、
このときに proto ファイル import google/protobuf/timestamp.proto
が読込めないせいで以下のようにクラスファイル変換のコンパイルに失敗していました。(このときはこの行自体をコメントアウトしてやり過ごしていましたが・・・)
> protoc -I=./ --csharp_out=./ ./addressbook.proto google/protobuf/timestamp.proto: File not found. addressbook.proto: Import "google/protobuf/timestamp.proto" was not found or had errors. addressbook.proto:49:3: "google.protobuf.Timestamp" is not defined.
今回、ちょっとこの Timestamp
という型を使ってみたくなったので、解決策を模索しました。
コンパイル時にパスを指定する
結論から言うと、以下の issue に書かれている通りです。
以下のように --proto_path
オプションを使用してコンパイルします。
(ここでは $(NuGetPackageRoot)
を C:\Users\<ユーザー名>\.nuget\packages
とします)
> protoc -I=./ --proto_path=`$(NuGetPackageRoot)/google.protobuf.tools/3.5.1/tools` --csharp_out=./ ./addressbook.proto
$(NuGetPackageRoot)/google.protobuf.tools/3.5.1/tools
内に、くだんの google/protobuf/timestamp.proto
が存在するからです。
要は、 proto ファイルでの import
は、コンパイル時に外部の定義先を指定することが必須のようですね。
Timestamp 型とはそもそも何モノ?
proto ファイル上では、以下のように定義されています。
message Timestamp { // Represents seconds of UTC time since Unix epoch // 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to // 9999-12-31T23:59:59Z inclusive. int64 seconds = 1; // Non-negative fractions of a second at nanosecond resolution. Negative // second values with fractions must still have non-negative nanos values // that count forward in time. Must be from 0 to 999,999,999 // inclusive. int32 nanos = 2;
seconds
フィールドnonos
フィールド- XXXミリ秒YYYマイクロ秒ZZZナノ秒を、
XXX,YYY,ZZZ
の9桁の整数として表すもの
- XXXミリ秒YYYマイクロ秒ZZZナノ秒を、
つまり、なんてことない、結構プリミティブ型に近いような拡張型ですね。
C# での使い方( DateTime
型との互換)
C# での時間は DateTime 型が良く使われると思います。
この互換については、Timestamp クラスに静的メソッドとして以下が用意されているので、双方簡単に変換ができます。
- Timestamp型を返す
FromDateTime(DateTime dateTime)
- DateTime型を返す
ToDateTime()
詳細は、以下を参照してください。
Google.Protobuf.WellKnownTypes.Timestamp Class Reference | Protocol Buffers | Google Developers
ハマったこと・・・
ProtocolBuffers はバイナリにシリアライズする規格です。しかし、誤って文字列にシリアライズしてしまっていました。
たまたまかもしれませんが、プリミティブ型を文字列にシリアライズしても、正常にデシリアライズできていました。そこで Timestamp 型を文字列にシリアライズすると例外も出ずに失敗してしまい、「なぜ Timestamp 型を使用するとシリアライズできなくなるのか・・・」とハマってしまったので備忘録として残しておきます・・・。
Pandoc で PlantUML を出力
pandoc は、当然ですがデフォルトでは plantuml に対応していません。
しかし、 markdown でドキュメントを書く際は、 plantuml をよく使用するので、 plantuml の画像を出力できるようにします。
前提
お約束の前提ですが、以下の環境とします。
- Windows 10 Home 64bit
また、あらかじめ以下もインストール済みとします。
- graphviz (plantuml を扱うのに必要)
python3 (pandoc のフィルターに使用)- 結果的に python は使用しませんでした
- node.js (npm を使用するのに必要)
plantuml とは
plantuml がどんなもので、plantuml そのものをどうやってインストールするかは省略します。
詳しくは↓サイトに紹介されています。
pandoc の plantuml 用フィルターを利用
Windows 環境下で pandoc の plantuml フィルターの用意が非常に大変でした。ネットの日本語情報も少なく、その情報も自分の環境ではうまくいかないものばかりだったので、備忘録として経緯も載せます。
pandoc バージョンの注意
私の環境では最初、 pandoc のバージョンが 1.7 でした。そのバージョンではどうやら -F XXX.py
という感じで python ファイルのフィルターが使用できないみたいでした。
バージョンを 2.1.2 にすると解決しました。
(すみません、参考サイトは失念しました。どこかの github の issue だった気がします)
plantuml-filter.py を使用する方法 その1(結果失敗です)
これは結果的に失敗したので、読み飛ばしてもらってOKです。
以下にある情報をもとにやってみました。
mickey-happygolucky.hatenablog.com
https://raw.githubusercontent.com/matthiasbeyer/pandoc-paper-template/master/scripts/plantuml-filter.pyにあるものをフィルターとして使用する方法です。
これはどうやら Windows 環境ではうまくいかないようで、実行すると以下のようなエラーが出ました。
> pandoc test.md -o test.html --self-contained -t html5 -F .\plantuml-filter.py [PLTUML] plantuml-images/8428a0c71ace69322a85c178b192bb8cdaa0bd20.png Traceback (most recent call last): File ".\plantuml-filter.py", line 64, in <module> toJSONFilter(graphviz) (中略) File "C:\Users\XXX\AppData\Local\Programs\Python\Python35-32\lib\subprocess.py", line 873, in __init__ "close_fds is not supported on Windows platforms" ValueError: close_fds is not supported on Windows platforms if you redirect stdin/stdout/stderr Error running filter .\plantuml-filter.py: Filter returned error status 1
どうやら python のスクリプトの中身が Windows に対応していないみたいです。(close_fds
が Windows では使えないっぽい?) python 自体わかっていない人間なので、いったんここで断念します。
※ python をちゃんと理解していたらチョコっと手を加えたら解決する可能性があります。
plantuml-filter.py を使用する方法 その2(結果失敗です)
これも結果的に失敗したので、読み飛ばしてもらってOKです。
以下にある情報をもとにやってみました。
これは inkscape とかの連動をしているので、そのまま流用することはできないのですが、ここでは「その1」であった python スクリプトを Windows 用に書き換えて使用する例が載っていました。
が、しかし実行すると以下のエラーが出てうまくいきませんでした。(念のため inkscape に関連する箇所はコメントアウトしたんですが、駄目でした)
> pandoc test.md -o test.html --self-contained -t html5 -F .\plantuml-filter.py Traceback (most recent call last): File ".\plantuml-filter.py", line 64, in <module> toJSONFilter(graphviz) (中略) File ".\plantuml-filter.py", line 47, in graphviz data, err = pipe(["java", "-jar", "C:\plantuml.jar", "-pipe", "-Tsvg", "-charset", "UTF-8"], code) File ".\plantuml-filter.py", line 22, in pipe p = subprocess.Popen(cmd, shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) File "C:\Users\XXX\AppData\Local\Programs\Python\Python35-32\lib\subprocess.py", line 950, in __init__ restore_signals, start_new_session) File "C:\Users\XXX\AppData\Local\Programs\Python\Python35-32\lib\subprocess.py", line 1220, in _execute_child startupinfo) FileNotFoundError: [WinError 2] 指定されたファイルが見つかりません。 Error running filter .\plantuml-filter.py: Filter returned error status 1
このエラーはよくわかりませんでした。一応 plantuml,jar
のファイルのパス等を確認したのですが、ファイルが見つかりませんと言われます。
まあよくわかりもせずに、他の人のスクリプトを使うなということです・・・。
pandoc-plantuml-filter.cmd を使用する方法(成功しました)
以下の github 上に公開されているリポジトリを参照させてもらいました。
pandoc-plantuml-filterの取得
Readme.md には npm -g
でグローバルにインストールするように書かれていますが、私の環境ではグローバルインストールではうまくいきませんでした。以下のように、markdown → html 変換するディレクトリにに配置します。
> npm install pandoc-plantuml-filter
実行
Readme に書いてある通り、以下の通り実行します。
> pandoc test.md -o test.html --self-contained -t html5 -F pandoc-plantuml-filter.cmd [WARNING] This document format requires a nonempty <title> element. Please specify either 'title' or 'pagetitle' in the metadata. Falling back to 'test'
なんか警告が出ていますが・・・ --metadata pagetitle=<ページタイトル>
を付加すると消えます。どうやら、ブラウザ上に表示されるタイトルの設定のようですが、はっきり言って勝手に html の名称を割り当ててくれたらいいのに・・・と思いますので、別途バッチファイルとか作ったほうが便利かもしれません。
(ちなみに、これは pandoc 側の仕様らしい?です。 issueでも同じ不満を言っている人がいますw)
追記
以下のバッチファイルを作ってみました。
# pandoc_markdown2html.bat @echo off rem param1: markdownファイル名 rem param2: cssファイル名 if "%1"=="" ( echo ERROR : Needs Filename. exit /b 1 ) if not "%2"=="" ( rem 第2引数はcssだけ許可 if not "%~x2"==".css" ( echo ERROR : Arg2 is neet to css filename. exit /b 1 ) set CSS=-c %2 ) rem ファイル名から拡張子を取り除く for /f %%i in ('echo %1') do set FILE=%%~ni pandoc %1 -o %FILE%.html --self-contained -t html5 %CSS% -F pandoc-plantuml-filter.cmd --metadata pagetitle="%FILE%"
使用例:
> pandoc_markdown2html.bat test.md test.css
plantuml を svg 形式で出力
pandoc-plantuml-filter のデフォルトのままでは、出力形式は png 固定です。
ちょこっといじって svg で出力するようにしました。
node_modules\pandoc-plantuml-filter\plantuml-filter.js
の以下の部分を書き換えます。
- var res = execSync(util.format("java -splash:no -jar \"%s\" -charset UTF-8 -pipe", plantumlPath), { input: umlText }); + var res = execSync(util.format("java -splash:no -jar \"%s\" -charset UTF-8 -pipe -Tsvg", plantumlPath), { input: umlText }); - var fileName = util.format("%d.png", imgCounter++); + var fileName = util.format("%d.svg", imgCounter++);
とりあえず、これで晴れて目的を達成できました。最終的には gitlab にプッシュしたら、 gitlab runner が走って markdown を html に自動変換するっていうのを実現したいです。
plantuml で日本語を扱う
plantuml で日本語の仕方を忘れていたので備忘録として残します。
ここでは、単体で plantuml を扱う場合です。(plantuml.jar
を使用する場合)
ソースファイルは UTF-8 とします。
java -jar .\plantuml.jar <ソースファイル> -charset UTF-8
Pandoc を使って、Markdown を HTML に変換する
主題の通り、 Pandoc というツールを使って Markdown 形式のファイルを、HTML形式に変換します。
前提
環境は、例によってWindows 10 Home 64bit です。
Pandoc のインストール
- github pandoc から最新版の Pandoc-XXX-windows.msi を DL
- DL した msi ファイルを実行し、インストール
- システム環境変数
Path
に、%USERPROFILE%\AppData\Local\Pandoc
を追加する - コマンドプロンプトを起動し、
pandoc --version
が実行できることを確認
追記
最新版(とりあえずVer2.1.2)に更新したりすると、うまくインストールされない場合がありました。
なぜか1回アンインストールした後再度インストールしなおしたら %USERPROFILE%\AppData\Local\Pandoc
に展開されたので、失敗した場合は上記方法を繰り返してみたらいいかもしれない。
参考
実行方法
基本的な使い方
以下を実行するだけです。
pandoc <Markdownファイル名> -o <アウトプットファイル名>
アウトプットファイル名に XXX.docx
とやると、docx 形式のファイルに変換されるし、
XXX.html
とやると、 html 形式で変換されます。
とても簡単です。
html 形式における画像の埋め込み
上記の実行だけでは、画像がリンクとして貼られてしまいます。
第3者へ配布する等の目的がある場合は、画像は埋め込みになっているほうがいい場合があります。
埋め込みには、以下の通り --self-contained
オプションを付加します。
pandoc test.md --serlf-contained -o test.html
独自 css の利用
そのままでは css が味気ないです。
以下の通り -c XXX.css
で独自の css を利用して html を出力できます。ついでに -t html5
としておくと、 html5 に対応可能となります。
pandoc test.md --serlf-contained -c xxx.css -t html5 -o test.html
とりあえず以上です。