我正在为派生类测试模拟 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 版本。2.3.1
- JustMock 版本。2017.3.913.1
发现
- 没有模拟 SQL 连接的测试将运行,但结果似乎被忽略了。如果您将鼠标悬停在测试图标上,它会说它在上次测试运行中没有被执行。将行添加到模拟 SQLConnection 将使其他测试运行。
- 如果将派生类方法更改为 return
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 的问题。谷歌搜索没有提供太多信息,因此任何见解将不胜感激。
更新 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 后,测试现在似乎没有完成运行。断言语句在向它们添加断点时会受到影响,但测试会在跨过断言后继续运行。
- 将模拟代码添加到另一个测试现在似乎没有什么不同,两个测试都将无限期地运行。