在编写单元测试用例以测试引发的异常时,尝试通过xUnit在以下两种方法中使用
以下是代码
public class Me : Entity, IAggregateRoot
{
public string Name {get; }
private List<Friend> friends;
public IReadonlyCollection<Friend> Friends => friends;
public Me(string name)
{
Name = name;
friends = new List<Friend>();
}
public void AddFriend(Friend friend)
{
if(friend.Type != "UnKnown")
friend.Add(friend);
else
throw new Exception("Cannot add a unknown friend.");
}
}
public class Friend
{
public string Name {get; }
public string Type {get; }
public Friend(string name, string type)
{
Name = name;
Type = type;
}
}
using System;
using MediatR;
using System.Collections.Generic;
public abstract class Entity
{
int? _requestedHashCode;
int _Id;
public virtual int Id
{
get
{
return _Id;
}
protected set
{
_Id = value;
}
}
private List<INotification> _domainEvents;
public IReadOnlyCollection<INotification> DomainEvents => _ domainEvents?.AsReadOnly();
public void AddDomainEvent(INotification eventItem)
{
_domainEvents = _domainEvents ?? new List<INotification>();
_domainEvents.Add(eventItem);
}
public void RemoveDomainEvent(INotification eventItem)
{
_domainEvents?.Remove(eventItem);
}
public void ClearDomainEvents()
{
_domainEvents?.Clear();
}
public bool IsTransient()
{
return this.Id == default(Int32);
}
public override bool Equals(object obj)
{
if (obj == null || !(obj is Entity))
return false;
if (Object.ReferenceEquals(this, obj))
return true;
if (this.GetType() != obj.GetType())
return false;
Entity item = (Entity)obj;
if (item.IsTransient() || this.IsTransient())
return false;
else
return item.Id == this.Id;
}
public override int GetHashCode()
{
if (!IsTransient())
{
if (!_requestedHashCode.HasValue)
_requestedHashCode = this.Id.GetHashCode() ^ 31;
return _requestedHashCode.Value;
}
else
return base.GetHashCode();
}
public static bool operator ==(Entity left, Entity right)
{
if (Object.Equals(left, null))
return (Object.Equals(right, null)) ? true : false;
else
return left.Equals(right);
}
public static bool operator !=(Entity left, Entity right)
{
return !(left == right);
}
}
public interface IAggregateRoot
{}//its empty
测试案例1:使用Assert.Throws
[Fact]
public void add_friend_business_rule_validation_throws_exception1()
{
var me = new Me("mady");
var friend = new Friend("johnDoe","UnKnown");
Assert.Throws<Exception>(() => me.AddFriend(friend));
}
测试案例2:使用Record.Exception
[Fact]
public void add_friend_business_rule_validation_throws_exception()
{
var me = new Me("mady");
var friend = new Friend("johnDoe","UnKnown");
var ex = Record.Exception(() => me.AddFriend(friend));
Assert.NotNull(ex);
Assert.IsType<Exception>(ex);
}
我想编写一个单元测试用例以测试所提供代码的异常。我的期望是,当尝试向集合中添加实体时,代码应在验证失败时引发异常。
问题:这里的测试用例没有失败且没有通过。执行停在下一行。
throw new Exception("Cannot add a unknown friend.");
当您没有尝试捕获块来捕获它时,就会发生这种情况。我期望xUnit Assert.Throws和Record.Exception会捕获该异常,但事实并非如此。
注意:提供的代码与实际代码非常接近,实体名称有所不同,并且通过删除不必要的代码得以简化。
我看过以下文档
编辑: 在运行测试时,xUnit的Assert.Throws和Record.Exception行为符合预期。
问题涉及调试测试。
如前所述,测试用例没有失败,也没有通过。每当任何一行代码抛出异常时,最近的catch块都应捕获该异常。基于文档和用户体验,我对xUnit Assert.Throws和Record.Exception有类似的期望。但是,调试测试时并非如此。
另一种众所周知的方法来演示问题和行为期望。
[Fact]
public void add_friend_business_rule_validation_throws_exception1()
{
var me = new Me("mady");
var friend = new Friend("johnDoe","UnKnown");
Exception expectedException = null;
try
{
me.AddFriend(friend); //exception thrown block
}
catch(Exception ex)//exception catched - control not stopped
{
expectedException = ex;
}
Assert.NotNull(expectedException);
Assert.IsType<Exception>(expectedException);
}
答案 0 :(得分:0)
在运行测试时,xUnit的Assert.Throws和Record.Exception行为符合预期。
问题涉及调试测试。
我能够通过从抛出异常的行开始逐步调试测试。在看到控件停在该行之后,请按F8或F5继续以进行测试。
throw new Exception("Cannot add a unknown friend.");