C# (dotnetcore)で標準出力を利用して進行中のスピナーを作る (5)
前回の記事
課題
- Consoleへの操作部分のテストをどうするか。
一つの解決策
Console.SetOutを利用して、Console.Outの出力先を変えてしまう。
[Fact] public void ConsoleTest() { var output = new System.IO.StringWriter(); Console.SetOut(output); ConsoleProgressSpiner c = new ConsoleProgressSpiner(); c.Minimum = 0; c.Maximum = 100; Assert.Equal("", output.ToString()); c.Value = 0; Assert.Equal("⠋ 0%", output.ToString()); }
MinimumとMaximumの設定時にも、updateを走らせていたが、これを廃止
テストしてみるとエラーになったので、少し修正した。
/// <summary>コンソール用の</summary> public class ConsoleProgressSpiner { //アニメーションのコマ string[] bars = { "⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏" }; private int minimum = 0; /// <summary>コントロールの範囲の最小値を取得または設定します。</summary> public int Minimum { get { return minimum; } set { if (value < 0) throw new ArgumentException("プロパティに対して指定された値が 0 未満です。"); minimum = value; if (this.minimum > this.value) { this.value = this.minimum; } } } private int maximum = 100; /// <summary>コントロールの範囲の最大値を取得または設定します。</summary> public int Maximum { get { return maximum; } set { if (value < 0) throw new ArgumentException("プロパティに対して指定された値が 0 未満です。"); maximum = value; if (this.maximum < this.value) { this.value = this.maximum; } } } private int value = 0; /// <summary>プログレス バーの現在位置を取得または設定します。</summary> public int Value { get { return this.value; } set { if (value < this.Minimum) throw new ArgumentException("指定された値が Minimum プロパティの値未満です。"); if (value > this.Maximum) throw new ArgumentException("指定された値が Maximum プロパティの値を超えます。"); this.value = value; update(); } } /// <summary>PerformStep() メソッドを呼び出したときに、プログレス バーの現在の位置を進める量を取得または設定します。</summary> public int Step { get; set; } /// <summary>プログレス バーの現在位置を Step プロパティの値の分だけ進めます。 </summary> public void PerformStep() { } /// <summary>Minimum〜Maximumに対するValueの進捗率を計算して返却</summary> /// <returns>進捗率(%)</returns> private int CalcProportion() { decimal oneMeter = new decimal(100) / (this.Maximum - this.Minimum); return Decimal.ToInt32(oneMeter * (this.Value - this.Minimum)); } /// <summary>進捗終了の印字</summary> private void DoneProgressConsoleWrite() { //色を戻す Console.ResetColor(); //カーソル位置を変更 Console.SetCursorPosition(0, Console.CursorTop); //終了の表示 Console.WriteLine("Done! "); } /// <summary>進捗進行中の印字</summary> private void InProgressConsoleWrite() { //進捗率計算 int proportion = CalcProportion(); //カーソル位置を変更 Console.SetCursorPosition(0, Console.CursorTop); //色変更 Console.ForegroundColor = ConsoleColor.Green; Console.BackgroundColor = ConsoleColor.Black; //進捗率の印字 Console.Write("{0}{1, 3:d0}%", bars[proportion % bars.Length], proportion); } /// <summary>描画</summary> private void update() { if (this.Maximum == this.Value) { DoneProgressConsoleWrite(); } else { InProgressConsoleWrite(); } } }
スピナーが1週回るまでテストを書いてみる
[Fact] public void ConsoleTest() { var output = new System.IO.StringWriter(); Console.SetOut(output); ConsoleProgressSpiner c = new ConsoleProgressSpiner(); c.Minimum = 0; c.Maximum = 100; Assert.Equal("", output.ToString()); c.Value = 0; Assert.Equal("⠋ 0%", output.ToString()); c.Value = 1; Assert.Equal("⠋ 0%⠙ 1%", output.ToString()); c.Value = 2; Assert.Equal("⠋ 0%⠙ 1%⠹ 2%", output.ToString()); c.Value = 3; Assert.Equal("⠋ 0%⠙ 1%⠹ 2%⠸ 3%", output.ToString()); c.Value = 4; Assert.Equal("⠋ 0%⠙ 1%⠹ 2%⠸ 3%⠼ 4%", output.ToString()); c.Value = 5; Assert.Equal("⠋ 0%⠙ 1%⠹ 2%⠸ 3%⠼ 4%⠴ 5%", output.ToString()); c.Value = 6; Assert.Equal("⠋ 0%⠙ 1%⠹ 2%⠸ 3%⠼ 4%⠴ 5%⠦ 6%", output.ToString()); c.Value = 7; Assert.Equal("⠋ 0%⠙ 1%⠹ 2%⠸ 3%⠼ 4%⠴ 5%⠦ 6%⠧ 7%", output.ToString()); c.Value = 8; Assert.Equal("⠋ 0%⠙ 1%⠹ 2%⠸ 3%⠼ 4%⠴ 5%⠦ 6%⠧ 7%⠇ 8%", output.ToString()); c.Value = 9; Assert.Equal("⠋ 0%⠙ 1%⠹ 2%⠸ 3%⠼ 4%⠴ 5%⠦ 6%⠧ 7%⠇ 8%⠏ 9%", output.ToString()); c.Value = 10; Assert.Equal("⠋ 0%⠙ 1%⠹ 2%⠸ 3%⠼ 4%⠴ 5%⠦ 6%⠧ 7%⠇ 8%⠏ 9%⠋ 10%", output.ToString()); }
少し不細工。
だけど、毎回 var output = new System.IO.StringWriter();
するのは少し違う気もする。
MinimumとMaximumを変更してのテスト
0〜500までの数字で、100%までの進捗率を求める部分の試験
[Fact] public void ConsoleCalcTest() { var output = new System.IO.StringWriter(); Console.SetOut(output); ConsoleProgressSpiner c = new ConsoleProgressSpiner(); c.Minimum = 0; c.Maximum = 500; Assert.Equal("", output.ToString()); c.Value = 0; Assert.Equal("⠋ 0%", output.ToString()); c.Value = 1; Assert.Equal("⠋ 0%⠋ 0%", output.ToString()); c.Value = 2; Assert.Equal("⠋ 0%⠋ 0%⠋ 0%", output.ToString()); c.Value = 3; Assert.Equal("⠋ 0%⠋ 0%⠋ 0%⠋ 0%", output.ToString()); c.Value = 4; Assert.Equal("⠋ 0%⠋ 0%⠋ 0%⠋ 0%⠋ 0%", output.ToString()); c.Value = 5; Assert.Equal("⠋ 0%⠋ 0%⠋ 0%⠋ 0%⠋ 0%⠙ 1%", output.ToString()); c.Value = 6; Assert.Equal("⠋ 0%⠋ 0%⠋ 0%⠋ 0%⠋ 0%⠙ 1%⠙ 1%", output.ToString()); c.Value = 7; Assert.Equal("⠋ 0%⠋ 0%⠋ 0%⠋ 0%⠋ 0%⠙ 1%⠙ 1%⠙ 1%", output.ToString()); c.Value = 8; Assert.Equal("⠋ 0%⠋ 0%⠋ 0%⠋ 0%⠋ 0%⠙ 1%⠙ 1%⠙ 1%⠙ 1%", output.ToString()); c.Value = 9; Assert.Equal("⠋ 0%⠋ 0%⠋ 0%⠋ 0%⠋ 0%⠙ 1%⠙ 1%⠙ 1%⠙ 1%⠙ 1%", output.ToString()); c.Value = 10; Assert.Equal("⠋ 0%⠋ 0%⠋ 0%⠋ 0%⠋ 0%⠙ 1%⠙ 1%⠙ 1%⠙ 1%⠙ 1%⠹ 2%", output.ToString()); }
ひとまず。ここまで。続きは次回。