JustMock и XUnit - производные результаты тестов классов игнорируются при имитации SQLConnection

Я высмеиваю SQLConnection для своих тестов производного класса и заметил, что XUnit(?), Похоже, игнорирует результаты.

Пример для воспроизведения поведения:

using System.Data.SqlClient;
using System.Threading.Tasks;
using Telerik.JustMock;
using Xunit;

namespace JustMockTesting {

    public abstract class BaseClass {
        protected abstract Task<int> ConnectTask();
    }

    public class Derived1 : BaseClass {
        protected override Task<int> ConnectTask() {
            return Task.FromResult( 1 );
        }
    }

    public class Derived2 : BaseClass {
        protected override Task<int> ConnectTask() {
            return Task.FromResult( 2 );
        }
    }

    public class Derived1Tests {
        private Derived1 derived1;

        public Derived1Tests() {
            derived1 = Mock.Create<Derived1>();
        }

        [Fact]
        public void Test1() {
            Mock.NonPublic.Arrange( derived1, "ConnectTask" ).CallOriginal();
            Mock.Arrange( () => Mock.Create<SqlConnection>().Open() ).DoNothing();

            Task<int> i = (Task<int>)new PrivateAccessor( derived1 ).CallMethod( "ConnectTask" );

            Assert.Equal( 1, i.Result );
        }
    }

    public class Derived2Tests {
        private Derived2 derived2;

        public Derived2Tests() {
            derived2 = Mock.Create<Derived2>();
        }

        [Fact]
        public void Test2() {
            Mock.NonPublic.Arrange( derived2, "ConnectTask" ).CallOriginal();
            //Mock.Arrange( () => Mock.Create<SqlConnection>().Open() ).DoNothing();

            Task<int> i = (Task<int>)new PrivateAccessor( derived2 ).CallMethod( "ConnectTask" );

            Assert.Equal( 2, i.Result );
        }
    }
}

Среда

  • VS 2017 вер. 15.3.4
  • xunit и xunit.runner.visualstudio ver. 2.3.1
  • JustMock ver. 2017.3.913.1

Выводы

  • Тест без смоделированного SQL-соединения будет запущен, но результат, похоже, будет проигнорирован. Если вы наведите курсор мыши на значок теста, он скажет, что он не был выполнен при последнем запуске теста. Добавление строки в макет SQLConnection сделает другой тестовый прогон.
  • Похоже, что проблема не возникает, если вы измените методы производного класса для возврата int вместо Task<int>,
  • Следующее исключение иногда будет выдаваться (оставшаяся часть трассировки пропущена, чтобы сохранить сообщение коротким):

    System.ArgumentException : 'this' type cannot be an interface itself.
    Stack Trace:
         at System.RuntimeTypeHandle.VerifyInterfaceIsImplemented(RuntimeTypeHandle handle, RuntimeTypeHandle interfaceHandle)
         at System.RuntimeTypeHandle.VerifyInterfaceIsImplemented(RuntimeTypeHandle interfaceHandle)
    

Не уверен, что это проблема с JustMock или XUnit. Google не предоставил много информации, поэтому любая оценка будет оценена.

Обновление 1 - пример на основе комментариев @Nkosi:

public abstract class BaseClass {
    protected abstract Task<bool> ConnectTask();
}

public class Derived1 : BaseClass {
    protected async override Task<bool> ConnectTask() {
        return await Task.FromResult( true );
    }
}

public class Derived2 : BaseClass {
    protected async override Task<bool> ConnectTask() {
        using ( SqlConnection conn = new SqlConnection( "someConnectionString" ) ) {
            try {
                conn.Open();
                return await Task.FromResult( true );
            } catch  {
                return await Task.FromResult( false );
            }
        }
    }
}

public class Derived1Tests {
    private Derived1 derived1;

    public Derived1Tests() {
        derived1 = Mock.Create<Derived1>();
    }

    [Fact]
    public async Task Test1() {
        Mock.NonPublic.Arrange( derived1, "ConnectTask" ).CallOriginal();

        //SqlConnection mockSqlConnection = Mock.Create<SqlConnection>();
        //Mock.Arrange( () => mockSqlConnection.Open() ).DoNothing();
        //Mock.Arrange( () => mockSqlConnection.Close() ).DoNothing();
        //Mock.Arrange( () => new SqlConnection( Arg.IsAny<string>() ) ).Returns( mockSqlConnection );

        bool b = await (Task<bool>)new PrivateAccessor( derived1 ).CallMethod( "ConnectTask" );

        Assert.True( b );
    }
}

public class Derived2Tests {
    private Derived2 derived2;

    public Derived2Tests() {
        derived2 = Mock.Create<Derived2>();
    }

    [Fact]
    public async Task Test2() {
        Mock.NonPublic.Arrange( derived2, "ConnectTask" ).CallOriginal();

        SqlConnection mockSqlConnection = Mock.Create<SqlConnection>();
        Mock.Arrange( () => mockSqlConnection.Open() ).DoNothing();
        Mock.Arrange( () => mockSqlConnection.Close() ).DoNothing();
        Mock.Arrange( () => new SqlConnection( Arg.IsAny<string>() ) ).Returns( mockSqlConnection );

        bool b = await (Task<bool>)new PrivateAccessor( derived2 ).CallMethod( "ConnectTask" );

        Assert.True( b );
    }
}

Выводы

  • Похоже, что тесты не заканчиваются сейчас после переключения на async / await. Утверждения assert удаляются при добавлении к ним точек останова, но тесты продолжают выполняться после перехода через утверждения.
  • Добавление фиктивного кода в другой тест, похоже, теперь не имеет значения, оба теста будут работать бесконечно.

0 ответов

Другие вопросы по тегам