我认为这两个测试应该表现相同,事实上我已经使用MS Test在我的项目中编写了测试,但现在却发现它不像NUnit那样尊重预期的消息。
NUnit(失败):
[Test, ExpectedException(typeof(System.FormatException), ExpectedMessage = "blah")]
public void Validate()
{
int.Parse("dfd");
}
MS测试(传递):
[TestMethod, ExpectedException(typeof(System.FormatException), "blah")]
public void Validate()
{
int.Parse("dfd");
}
无论我给ms测试什么消息,它都会通过。
如果消息不对,有没有办法让ms测试失败?我甚至可以创建自己的异常属性吗?我宁愿不必为每次测试都写一个try catch块。
答案 0 :(得分:28)
我们在整个地方使用这个属性,我们明显误解了第二个参数(对我们感到羞耻)。
但是,我们肯定用它来检查异常消息。以下是我们使用此页面提示的内容。它不处理全球化或继承的异常类型,但它可以满足我们的需求。同样,目标是简单地将RR'ExpectedException'与此类交换出来。 (Bummer ExpectedException已被密封。)
public class ExpectedExceptionWithMessageAttribute : ExpectedExceptionBaseAttribute
{
public Type ExceptionType { get; set; }
public string ExpectedMessage { get; set; }
public ExpectedExceptionWithMessageAttribute(Type exceptionType)
{
this.ExceptionType = exceptionType;
}
public ExpectedExceptionWithMessageAttribute(Type exceptionType, string expectedMessage)
{
this.ExceptionType = exceptionType;
this.ExpectedMessage = expectedMessage;
}
protected override void Verify(Exception e)
{
if (e.GetType() != this.ExceptionType)
{
Assert.Fail(String.Format(
"ExpectedExceptionWithMessageAttribute failed. Expected exception type: {0}. Actual exception type: {1}. Exception message: {2}",
this.ExceptionType.FullName,
e.GetType().FullName,
e.Message
)
);
}
var actualMessage = e.Message.Trim();
if (this.ExpectedMessage != null)
{
Assert.AreEqual(this.ExpectedMessage, actualMessage);
}
Console.Write("ExpectedExceptionWithMessageAttribute:" + e.Message);
}
}
答案 1 :(得分:22)
mstest第二个参数是测试失败时打印出来的消息。如果抛出formatexception,mstest将成功。我发现这篇文章可能很有用
答案 2 :(得分:12)
@rcravens是正确的 - 第二个参数是在测试失败时打印的消息。我为解决这个问题所做的工作是我的测试方法略有不同。不可否认,我不喜欢这种方法,但它确实有用。
[TestMethod]
public void Validate()
{
try
{
int.Parse("dfd");
// Test fails if it makes it this far
Assert.Fail("Expected exception was not thrown.");
}
catch (Exception ex)
{
Assert.AreEqual("blah", ex.Message);
}
}
答案 3 :(得分:7)
我通过添加对contains,case-insensitive和ResourcesType-ResourceName组合的支持,扩展了BlackjacketMack对我们项目的回答。
用法示例:
public class Foo
{
public void Bar(string mode)
{
if (string.IsNullOrEmpty(mode)) throw new InvalidOperationException(Resources.InvalidModeSpecified);
}
public void Bar(int port)
{
if (port < 0 || port > Int16.MaxValue) throw new ArgumentOutOfRangeException("port");
}
}
[TestClass]
class ExampleClass
{
[TestMethod]
[ExpectedExceptionWithMessage(typeof(InvalidOperationException), typeof(Samples.Resources), "InvalidModeSpecified")]
public void Raise_Exception_With_Message_Resource()
{
new Foo().Bar(null);
}
[TestMethod]
[ExpectedExceptionWithMessage(typeof(ArgumentOutOfRangeException), "port", true)]
public void Raise_Exeception_Containing_String()
{
new Foo().Bar(-123);
}
}
这是更新的课程:
public class ExpectedExceptionWithMessageAttribute : ExpectedExceptionBaseAttribute
{
public Type ExceptionType { get; set; }
public Type ResourcesType { get; set; }
public string ResourceName { get; set; }
public string ExpectedMessage { get; set; }
public bool Containing { get; set; }
public bool IgnoreCase { get; set; }
public ExpectedExceptionWithMessageAttribute(Type exceptionType)
: this(exceptionType, null)
{
}
public ExpectedExceptionWithMessageAttribute(Type exceptionType, string expectedMessage)
: this(exceptionType, expectedMessage, false)
{
}
public ExpectedExceptionWithMessageAttribute(Type exceptionType, string expectedMessage, bool containing)
{
this.ExceptionType = exceptionType;
this.ExpectedMessage = expectedMessage;
this.Containing = containing;
}
public ExpectedExceptionWithMessageAttribute(Type exceptionType, Type resourcesType, string resourceName)
: this(exceptionType, resourcesType, resourceName, false)
{
}
public ExpectedExceptionWithMessageAttribute(Type exceptionType, Type resourcesType, string resourceName, bool containing)
{
this.ExceptionType = exceptionType;
this.ExpectedMessage = ExpectedMessage;
this.ResourcesType = resourcesType;
this.ResourceName = resourceName;
this.Containing = containing;
}
protected override void Verify(Exception e)
{
if (e.GetType() != this.ExceptionType)
{
Assert.Fail(String.Format(
"ExpectedExceptionWithMessageAttribute failed. Expected exception type: <{0}>. Actual exception type: <{1}>. Exception message: <{2}>",
this.ExceptionType.FullName,
e.GetType().FullName,
e.Message
)
);
}
var actualMessage = e.Message.Trim();
var expectedMessage = this.ExpectedMessage;
if (expectedMessage == null)
{
if (this.ResourcesType != null && this.ResourceName != null)
{
PropertyInfo resourceProperty = this.ResourcesType.GetProperty(this.ResourceName, BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
if (resourceProperty != null)
{
string resourceValue = null;
try
{
resourceValue = resourceProperty.GetMethod.Invoke(null, null) as string;
}
finally
{
if (resourceValue != null)
{
expectedMessage = resourceValue;
}
else
{
Assert.Fail("ExpectedExceptionWithMessageAttribute failed. Could not get resource value. ResourceName: <{0}> ResourcesType<{1}>.",
this.ResourceName,
this.ResourcesType.FullName);
}
}
}
else
{
Assert.Fail("ExpectedExceptionWithMessageAttribute failed. Could not find static resource property on resources type. ResourceName: <{0}> ResourcesType<{1}>.",
this.ResourceName,
this.ResourcesType.FullName);
}
}
else
{
Assert.Fail("ExpectedExceptionWithMessageAttribute failed. Both ResourcesType and ResourceName must be specified.");
}
}
if (expectedMessage != null)
{
StringComparison stringComparison = this.IgnoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal;
if (this.Containing)
{
if (actualMessage == null || actualMessage.IndexOf(expectedMessage, stringComparison) == -1)
{
Assert.Fail(String.Format(
"ExpectedExceptionWithMessageAttribute failed. Expected message: <{0}>. Actual message: <{1}>. Exception type: <{2}>",
expectedMessage,
e.Message,
e.GetType().FullName
)
);
}
}
else
{
if (!string.Equals(expectedMessage, actualMessage, stringComparison))
{
Assert.Fail(String.Format(
"ExpectedExceptionWithMessageAttribute failed. Expected message to contain: <{0}>. Actual message: <{1}>. Exception type: <{2}>",
expectedMessage,
e.Message,
e.GetType().FullName
)
);
}
}
}
}
}
答案 4 :(得分:4)
您可以使用this project中解释的this article中的代码创建ExpectedExceptionMessage属性,该属性将与MS Test一起使用以获得所需的结果。
毫秒测试(失败):
[TestClass]
public class Tests : MsTestExtensionsTestFixture
{
[TestMethod, ExpectedExceptionMessage(typeof(System.FormatException), "blah")]
public void Validate()
{
int.Parse("dfd");
}
}
答案 5 :(得分:1)
我曾经写过这篇文章,所以也许在VS2012中有更好的方法。
答案 6 :(得分:1)
试试这种现代方式:
[TestMethod]
public async Task DoSmthAsync_WithWrongParam_ThrowHttpRequestException()
{
var smbdTask = service.DoSmthAsync(/* call params */);
var exception = await Assert.ThrowsExceptionAsync<HttpRequestException>(() => smbdTask);
Assert.AreEqual(HttpStatusCode.NotFound, exception.StatusCode);
}
答案 7 :(得分:0)
试试这个。在此示例中,我有一条问候消息,显示给定名称的问候消息。当name参数为空或null时,系统会抛出带有消息的异常。 ExceptionAssert.Throws
在MsTest中验证。
[TestMethod]
public void Does_Application_Display_Correct_Exception_Message_For_Empty_String()
{
// Arrange
var oHelloWorld = new HelloWorld();
// Act
// Asset
ExceptionAssert.Throws<ArgumentException>(() =>
oHelloWorld.GreetingMessge(""),"Invalid Name, Name can't be empty");
}
[TestMethod]
public void Does_Application_Display_Correct_Exception_Message_For_Null_String()
{
// Arrange
var oHelloWorld = new HelloWorld();
// Act
// Asset
ExceptionAssert.Throws<ArgumentNullException>(() =>
oHelloWorld.GreetingMessge(null), "Invalid Name, Name can't be null");
}