JustMock and XUnit - Derived class test results getting ignored when mocking SQLConnection

447 Views Asked by At

I'm mocking SQLConnection for my derived class tests and noticed that it seems to make XUnit(?) ignore the results.

Example to reproduce behavior:

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

Environment

  • VS 2017 ver. 15.3.4
  • xunit and xunit.runner.visualstudio ver. 2.3.1
  • JustMock ver. 2017.3.913.1

Findings

  • The test without the mocked SQL connection will run but the result seems to get ignored. If you hover over the test icon, it'll say that it didn't get executed in the last test run. Adding the line to mock SQLConnection will make the other test run.
  • The issue doesn't seem to occur if you change the derived class methods to return int instead of Task<int>.
  • The following exception will get thrown sometimes (rest of the trace omitted to keep the post short):

    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)
    

Not sure if this is an issue with JustMock or XUnit. Googling hasn't provided much info so any insight would be appreciated.

Update 1 - Example based on @Nkosi's Comments:

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

Findings

  • The tests don't seem to finish running now after switching to async/await. The assert statements get hit when adding breakpoints to them but the tests continue running after stepping over the asserts.
  • Adding the mock code to the other test doesn't seem to make a difference now, both tests will run indefinitely.
0

There are 0 best solutions below