Почему это утверждение вызывает исключение формата при сравнении структур?
Я пытаюсь утверждать равенство двух System.Drawing.Size
структуры, и я получаю исключение формата вместо ожидаемого сбоя assert.
[TestMethod]
public void AssertStructs()
{
var struct1 = new Size(0, 0);
var struct2 = new Size(1, 1);
//This throws a format exception, "System.FormatException: Input string was not in a correct format."
Assert.AreEqual(struct1, struct2, "Failed. Expected {0}, actually it is {1}", struct1, struct2);
//This assert fails properly, "Failed. Expected {Width=0, Height=0}, actually it is {Width=1, Height=1}".
Assert.AreEqual(struct1, struct2, "Failed. Expected " + struct1 + ", actually it is " + struct2);
}
это предполагаемое поведение? Я делаю что-то не так здесь?
4 ответа:
я понял. И да, это ошибка.
проблема в том, что есть два уровня
string.Format
идем дальше.The первый уровень форматирования что-то вроде:
string template = string.Format("Expected: {0}; Actual: {1}; Message: {2}", expected, actual, message);
затем мы используем
string.Format
с параметрами, которые вы поставлены:string finalMessage = string.Format(template, parameters);
(культуры, разумеется, а некоторые вид очистки... но этого недостаточно.)
это выглядит нормально-если только ожидаемые и фактические значения сами по себе заканчиваются фигурными скобками, после преобразования в строку - что они делают для
Size
. Например, ваш первый размер в конечном итоге преобразуется в:{Width=0, Height=0}
Итак, второй уровень форматирования-это что-то вроде:
string.Format("Expected: {Width=0, Height=0}; Actual: {Width=1, Height=1 }; " + "Message = Failed expected {0} actually is {1}", struct1, struct2);
... и вот что удается. Ай.
действительно, мы можем доказать это очень легко, обманывая форматирование, чтобы использовать наши параметры для ожидаемого и фактического части:
var x = "{0}"; var y = "{1}"; Assert.AreEqual<object>(x, y, "What a surprise!", "foo", "bar");
результат:
Assert.AreEqual failed. Expected:<foo>. Actual:<bar>. What a surprise!
явно сломан, как мы и не ожидали
foo
и не было фактического значенияbar
!в основном это похоже на атаку SQL-инъекции, но в гораздо менее страшном контексте
string.Format
.в качестве обходного пути, вы можете использовать
string.Format
как предлагает StriplingWarrior. Это позволяет избежать второго уровня форматирования, выполняемого в результате форматирования с фактическими / ожидаемыми значениями.
Я думаю, что вы нашли ошибку.
это работает (выдает исключение assert):
var a = 1; var b = 2; Assert.AreEqual(a, b, "Not equal {0} {1}", a, b);
и это работает (выдает сообщение):
var a = new{c=1}; var b = new{c=2}; Console.WriteLine(string.Format("Not equal {0} {1}", a, b));
но это не работает (бросает!--4-->):
var a = new{c=1}; var b = new{c=2}; Assert.AreEqual(a, b, "Not equal {0} {1}", a, b);
Я не могу придумать ни одной причины, по которой это было бы ожидаемым поведением. Я бы отправил отчет об ошибке. В то же время, вот решение:
var a = new{c=1}; var b = new{c=2}; Assert.AreEqual(a, b, string.Format("Not equal {0} {1}", a, b));
Я согласен с @StriplingWarrior, что это действительно похоже на ошибку с утверждением.Метод AreEqual () по крайней мере на 2 перегрузках. Как уже указывал StiplingWarrior, следующее терпит неудачу;
var a = new { c = 1 }; var b = new { c = 2 }; Assert.AreEqual(a, b, "Not equal {0} {1}", a, b);
Я немного экспериментировал над этим дальше, будучи немного более явным в использовании кода. Следующее тоже не работает;
// specify variable data type rather than "var"...no effect, still fails Size a = new Size(0, 0); Size b = new Size(1, 1); Assert.AreEqual(a, b, "Not equal {0} {1}", a, b);
и
// specify variable data type and name the type on the generic overload of AreEqual()...no effect, still fails Size a = new Size(0, 0); Size b = new Size(1, 1); Assert.AreEqual<Size>(a, b, "Not equal {0} {1}", a, b);
это заставило меня задуматься. Система.Рисунок.Размер-это структура. Что о объекты? Список параметров тут укажите, что список после
string
сообщенииparams object[]
. Технически, да структурирует are объекты...но особенный видов объектов, т. е., типы значений. Я думаю, что это, где ошибка кроется. Если мы используем наш собственный объект с аналогичным использованием и структуройSize
, следующие На самом деле тут работы;private class MyClass { public MyClass(int width, int height) : base() { Width = width; Height = height; } public int Width { get; set; } public int Height { get; set; } } [TestMethod] public void TestMethod1() { var test1 = new MyClass(0, 0); var test2 = new MyClass(1, 1); Assert.AreEqual(test1, test2, "Show me A [{0}] and B [{1}]", test1, test2); }