xUnit Assert.Throws и Record.Exception не перехватывает исключение - PullRequest
0 голосов
/ 03 марта 2019

При написании модульного тестового примера для проверки сгенерированного исключения, попытались использовать оба метода ниже, используя xUnit

  1. Assert.Throws (действие)
  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.");

Это произойдет, когда у вас нет блока try catch, чтобы его перехватить.Я ожидаю, что xUnit Assert.Throws & Record.Exception поймает исключение, но это не так.

Примечание: Предоставленный код очень близок к реальному коду, причем имена сущностей являютсяотличается и упрощается удалением ненужного кода.

Я видел следующую документацию

  1. xUnit-Record.Exception Документация
  2. Утверждение исключения с помощью вопроса XUnit-Stackoverflow

РЕДАКТИРОВАТЬ: Поведение 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 голосов
/ 04 марта 2019

Поведение xUnit Assert.Throws & Record.Exception соответствует ожидаемому при выполнении тестов.

Проблема связана с тестами отладки.

Я смог отладить тест, перешагнув через строку исключения.После того, как вы увидите, что управление остановлено на линии, нажмите F8 или F5, чтобы продолжить, и тест будет выполнен.

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