1

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.
user7003875
  • 121
  • 6
  • Can you clarify? "The test without the mocked SQL connection won't get run." -- Are you sure it's not running at all, or is it running but not reporting that it ran in XUnit? For example, if you put a breakpoint in the test and run in a debugger, does it hit the breakpoint? – John M. Wright Dec 11 '17 at 20:18
  • Thanks for the reply @JohnM.Wright. Tried what you said and yes, the breakpoint does get hit but the results get ignored I guess. The test icon says the test wasn't executed in the last run. Updated the question. – user7003875 Dec 11 '17 at 20:29
  • @user7003875 How does SqlConnection even come into play here? The base and derived classes make no use of them. This question appears incomplete. – Nkosi Dec 11 '17 at 20:29
  • Tests should be converted to async and await the returned tasks. You seem to be mixing async and sync code. – Nkosi Dec 11 '17 at 20:33
  • I use the SqlConnection in the actual code I'm testing, the code above is just an example for someone to reproduce the issue. I'll convert them to use async/await and see what happens, thanks @Nkosi. – user7003875 Dec 11 '17 at 20:33
  • @user7003875 then the example is not accurate and thus unclear. – Nkosi Dec 11 '17 at 20:34
  • @Nkosi, doesn't the example show the issue that I'm bringing up though? I would think the 2 tests should still run regardless of the SqlConnection being used or not. – user7003875 Dec 11 '17 at 20:38
  • My problem is that I cannot see the relation/reason for even having the SqlConnection in the test as it plays not part if what was shown in the examples. – Nkosi Dec 11 '17 at 20:48
  • @Nkosi, Added a different example based on your comments. – user7003875 Dec 12 '17 at 04:28

0 Answers0