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 удаляются при добавлении к ним точек останова, но тесты продолжают выполняться после перехода через утверждения.
- Добавление фиктивного кода в другой тест, похоже, теперь не имеет значения, оба теста будут работать бесконечно.