はじめに
xUnit で [Theory]
を指定するテストメソッドでは [InlineData()]
を使用して、複数のテストケースを記述できます。
ですが引数が多くなってくると面倒で、楽をしたくなります。
いつものごとく、コードジェネレータを作成します。
コードジェネレータ
左の入力欄に、サンプルのように TSV 文字列をコピペして、convert ボタンをクリックしてください。右の入力欄に、生成した C# のコードが出力されます。
サンプル文字列が既に入力されているので、convert ボタンをクリックするだけで動作を確認できます。
生成されるコード例
以下のようなコードが出力されます。
[Theory()]
[InlineData(1, "Apple", 200)]
[InlineData(2, "Banana", 150)]
[InlineData(3, "Citrus", 300)]
public void TestMethod(int Id, string Name, int Price)
オプション
オプションが二つあり、チェックボックスで有効/無効を切り替えます。
Use CamelCase
チェックすると、メソッドの引数部分の識別子をキャメルケースにします。
Use String
チェックすると、全ての引数を文字列としてコードを生成します。
念のため、ソースコードも載っけておきます。JSFiddle がサービス終了しちゃうかもしれませんからね。
それに、オフラインで使いたいという要件もあるかもしれません(その場合、CDN のところは修正してください)。
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TSV (from Excel or other) to xUnit InlineData Definition</title>
<style>
.outer {
display: flex;
justify-content: center;
align-items: center;
}
#app {
margin: 0 auto;
display: inline-block;
text-align: left;
height: 95%;
}
textarea {
font-family: monospace;
}
@media (prefers-color-scheme: dark) {
body {
background-color: #333;
color: #fff;
}
textarea {
background-color: #444;
color: #fff;
}
}
</style>
</head>
<body>
<div class="outer">
<div id="app">
<table>
<tr>
<td rowspan="3">
<textarea name="" id="src" cols="30" rows="10" v-model="src" placeholder="Excel などからコピペしてください"></textarea>
</td>
<td></td>
<td rowspan="3">
<textarea name="" id="result" cols="30" rows="10" v-model="result"></textarea>
</td>
</tr>
<tr>
<td>
<input type="checkbox" id="useCamelCase" v-model="useCamelCase" />
<label for="useCamenCase">Use CamelCase</label>
<br />
<input type="checkbox" id="useString" v-model="useString" />
<label for="useString">Use String</label>
<br />
</td>
</tr>
<tr>
<td>
<button v-on:click="convert">convert</button><br />
<button v-on:click="copyResult">copy</button>
</td>
</tr>
</table>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<script>
var vm = new Vue({
el: "#app",
data: {
src: "Id\tName\tPrice\n1\tApple\t200\n2\tBanana\t150\n3\tCitrus\t300",
result: "",
ln: "grid",
useCamelCase: true,
useString: false,
},
methods: {
convert: function (e) {
let ret = '';
let lines = this.getLines();
const useCC = this.useCamelCase;
const useStr = this.useString;
ret = "[Theory()]\n";
lines.forEach((line, row) => {
if (row === 0) {return;}
var csv = [];
line.forEach((col, idx) => {
if (useStr || isNaN(col)) {
csv.push('"' + col + '"');
} else {
csv.push(col);
}
});
ret += "[InlineData(" + csv.join(', ') + ")]\n";
});
let types = [];
const isInt = function (src) {
const n = Number.parseFloat(src);
return Number(n) === n && n % 1 === 0;
};
lines[1].forEach((col, idx) => {
if (!this.useString && !isNaN(col)) {
if (isInt(col)) {
types.push('int');
} else {
types.push('double');
}
} else {
types.push('string');
}
});
ret += 'public void TestMethod(';
var params = [];
lines[0].forEach((col, idx) => {
if (useCC) {col = this.camelCase(col);}
params.push(types[idx] + ' ' + col);
});
ret += params.join(', ');
ret += ")\n";
this.result = ret;
},
getLines: function () {
var linesSrc = this.src.split("\n");
var lines = [];
linesSrc.forEach(line => {
if (line.trim() ==='') {return;}
lines.push(line.trim().split("\t"));
});
return lines;
},
camelCase: function (str){
str = String(str);
str = str.charAt(0).toLowerCase() + str.slice(1);
return str.replace(/[-_](.)/g, function(match, group1) {
return String(group1).toUpperCase();
});
},
copyResult: function () {
navigator.clipboard
.writeText(this.result)
.then(() => {
console.log('copied!')
})
.catch(e => {
console.error(e)
});
}
}
});
</script>
</body>
</html>
最後に
2021-11-30 バグ修正。
なんか Edge だとコピーができない。