xUnit Assert.Throws和Record.Exception不会捕获异常

时间:2019-03-03 20:39:53

标签: c# unit-testing asp.net-core-2.0 xunit.net mediatr

在编写单元测试用例以测试引发的异常时,尝试通过xUnit在以下两种方法中使用

  1. 断言(动作)
  2. Record.Exception(操作)

以下是代码

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会捕获该异常,但事实并非如此。

注意:提供的代码与实际代码非常接近,实体名称有所不同,并且通过删除不必要的代码得以简化。

我看过以下文档

  1. xUnit-Record.Exception Documentation
  2. Assert an Exception using XUnit- Stackoverflow question

编辑: 在运行测试时,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);
}

1 个答案:

答案 0 :(得分:0)

在运行测试时,xUnit的Assert.Throws和Record.Exception行为符合预期。

问题涉及调试测试。

我能够通过从抛出异常的行开始逐步调试测试。在看到控件停在该行之后,请按F8或F5继续以进行测试。

throw new Exception("Cannot add a unknown friend.");