たいちょーの雑記

ぼくが3日に一度くらい雑記をかくところ

競プロとかのテストケースを自動化したい

蜘蛛ってこわい

家蜘蛛っていいやつなのは知ってるけどデカいと怖い

テストケースを自動化したい

いまさら競プロを始めた隊長です
いまはABCを中心にやっています

基本的に
問題読む

コード書く(長考)
↓  ↑
問題のページに書いてあるテストケースを試す

提出

って流れですけどこの テストケースを試すとこが正直ダルい
そう思いませんか!?

なのでVisualStudioの単体テスト機能を使ってこれを自動化したいんですけど、ggってもあんまり出てこないので書きました。

自動化する

これをテストしたぃょ・・・

public class Calc{
    public void Solve(){
        var item=int.Parse(Console.ReadLine());
        Console.WriteLine(item);
        return;
    }
}

適当なテキストファイルにテストケースの入力と出力を一行開けて並べるだけで全部チェックしてほしぃょ・・・

123

123

456

456

↑のテキストファイルをtestcase.txtという名前でプロジェクトに追加して、以下の単体テストを実行すると・・・????

using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Text;
using System.IO;

namespace CS_AtCoder.Tests {
    [TestClass()]
    public class CalcTests {
        private static bool[] active = new bool[4] { false, false, false, false };
        private static StringBuilder[] expected = new StringBuilder[4];
        private static StringBuilder[] Stdin = new StringBuilder[4];
        private const string testcasePath = @"..\..\test_case.txt";
        Calc Target = new Calc();
        [ClassInitialize()]
        public static void ClassInit(TestContext tc) {
            int cnt = 0;
            string s;
            StreamReader sr = new StreamReader(testcasePath);
            while (sr.Peek() >= 0 && cnt < 4) {
                var sb = new StringBuilder();
                while ((s = sr.ReadLine()) != "" && sr.Peek() >= 0) {
                    sb.Append(s);
                }
                Stdin[cnt] = sb;
                StringBuilder expect = new StringBuilder();
                if (sr.Peek()<0) break;
                while (sr.Peek() >= 0 && (s = sr.ReadLine()) != "") {
                    expect.Append(s);
                }
                expected[cnt] = expect;
                active[cnt] = true;
                cnt++;
            }
            sr.Close();
        }

        private Tuple<StringWriter, StringReader, StringBuilder> MakeRedirect(int index) {
            var sb = new StringBuilder();
            var sr = new StringReader(Stdin[index].ToString());
            var sw = new StringWriter(sb);
            Console.SetIn(sr);
            Console.SetOut(sw);
            return new Tuple<StringWriter, StringReader, StringBuilder>(sw, sr, sb);
        }

        //↓と同じようなのを好きなだけ並べる
        [TestMethod]
        public void Case0() {
            int index = 0;
            if (!active[index]) { Assert.IsTrue(true);return; }
            var item = MakeRedirect(index);
            Target.Solve();
            item.Item1.Close();
            item.Item2.Close();
            var actual = item.Item3.ToString().Replace("\r\n", "");
            Assert.AreEqual(expected[index].ToString(), actual);
        }
    }
}

unittest1

やったあぁぁぁ

やってること

やってることはただ単にStringBuilderに入力と出力を格納し、入力の方をStringReaderとしてstdinに割り当てる。
もう一つStringBuilderを用意し、それをStringWriterとしてstdoutに割り当てる。これをほしい出力を格納したStringBuilderAssert.AreEqualしてあげるだけです。

ちなみにテストケースは5つ以上できません。
まあでもだいたい5つもないしな~みたいなw
余ったテストメソッドはIsTrueでOKだします

もう少しいい書き方もあるだろうけど、これで動くのでこれでいいです。 テストケースをコピペするのもなんか自動化できないかな~とか思いますけどまぁこれでいいです。

よーし!めっちゃはかどりそうです!