두 System.Drawing.Size
구조 의 동등성을 주장하려고하는데 예상되는 주장 실패 대신 형식 예외가 발생합니다.
[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);
}
의도 된 동작입니까? 내가 여기서 뭔가 잘못하고 있니?
답변
나는 그것을있어. 그리고 네, 그것은 버그입니다.
문제는 여기에 두 가지 수준이 string.Format
있다는 것입니다.
첫 번째 수준의 서식은 다음과 같습니다.
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가 제안한대로 사용할 수 있습니다 . 이렇게하면 실제 / 예상 값으로 서식을 지정한 결과에 대해 두 번째 수준의 서식이 수행되는 것을 방지 할 수 있습니다.
답변
버그를 찾은 것 같습니다.
이것은 작동합니다 (어설 션 예외 발생).
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));
그러나 이것은 작동하지 않습니다 (을 던졌습니다 FormatException
).
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에 동의합니다. 이것이 실제로 2 개 이상의 오버로드에서 Assert.AreEqual () 메서드의 버그 인 것처럼 보입니다. 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);
이것은 나를 생각하게했다. System.Drawing.Size는 구조체입니다. 물체는 어떻습니까? param 목록 은string
메시지 뒤의 목록 이 params object[]
. 기술적으로 yes 구조체 는 객체이지만 특별한 종류 의 객체, 즉 값 유형입니다. 나는 이것이 버그가있는 곳이라고 생각한다. 와 유사한 사용법과 구조를 가진 자체 객체를 사용 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);
}
답변
첫 번째 주장이 틀렸다고 생각합니다.
대신 사용 :
Assert.AreEqual(struct1,
struct2,
string.Format("Failed expected {0} actually is {1}", struct1, struct2));