简体   繁体   English

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

[英]xUnit Assert.Throws and Record.Exception does not catch exception

While writing unit test case to test thrown exception, have tried to use below both methods using xUnit 在编写单元测试用例以测试引发的异常时,尝试使用xUnit在以下两种方法中使用

  1. Assert.Throws(action) Assert.Throws(动作)
  2. Record.Exception(action) Record.Exception(动作)

Following is the code 以下是代码

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

Test Case 1: Using Assert.Throws 测试案例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));
}

Test Case 2: Using Record.Exception 测试案例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);
}

I would like to write a unit test case to test exception for the provided code. 我想编写一个单元测试用例以测试所提供代码的异常。 My expectation is the code should throw exception on validation fail when trying to add a entity to a collection. 我的期望是,当尝试向集合中添加实体时,代码应在验证失败时引发异常。

Issue: The test cases here are not failing neither passing. 问题:这里的测试用例没有失败且没有通过。 The execution is stalled at following line. 执行停在下一行。

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

This will happen when you have no try catch block to catch it. 当您没有尝试捕获块来捕获它时,就会发生这种情况。 I'm expecting xUnit Assert.Throws & Record.Exception will catch the exception but it is not. 我期望xUnit Assert.Throws&Record.Exception将捕获该异常,但事实并非如此。

Note: The code provided is very close to the actual code, with entity names being different and simplified by removing unnecessary code. 注意:提供的代码与实际代码非常接近,实体名称不同,并且通过删除不必要的代码来简化实体名称。

I have seen the following documentation 我看过以下文件

  1. xUnit-Record.Exception Documentation xUnit-Record.Exception文档
  2. Assert an Exception using XUnit- Stackoverflow question 使用XUnit声明异常-Stackoverflow问题

EDIT: The xUnit Assert.Throws & Record.Exception behavior is as expected while I Run Tests. 编辑: xUnit Assert.Throws&Record.Exception行为是按预期方式,当我运行测试。

Issue is with debugging tests. 问题在于调试测试。

As mentioned test cases were are not failing neither passing. 如前所述,测试用例没有失败也没有通过。 Whenever any line of code throws exception the nearest catch block shall catch the exception. 每当任何一行代码抛出异常时,最近的catch块都应捕获该异常。 I have similar expectation from xUnit Assert.Throws & Record.Exception based on documentation and user experience. 基于文档和用户体验,我对xUnit Assert.Throws和Record.Exception有类似的期望。 However this is not the case while debugging test. 但是,调试测试时不是这种情况。

An alternate & well known approach to demonstrate the problem and expectation of behavior. 另一种众所周知的方法来演示问题和行为期望。

[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);
}

The xUnit Assert.Throws & Record.Exception behavior is as expected while I Run Tests. 我运行测试时,xUnit Assert.Throws和Record.Exception行为是预期的。

Issue is with debugging tests. 问题在于调试测试。

I was able to debug the test by stepping over from the exception thrown line. 通过从抛出异常的行开始,我能够调试测试。 After you see the control stopped at the line, press F8 or F5 to continue and test will be executed. 看到控件停在该行后,按F8或F5继续,将执行测试。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM