Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EffortException while running unit tests #42

Open
rosieks opened this issue Jul 20, 2016 · 13 comments
Open

EffortException while running unit tests #42

rosieks opened this issue Jul 20, 2016 · 13 comments
Assignees
Labels

Comments

@rosieks
Copy link

rosieks commented Jul 20, 2016

Hi,
I'm using Effort to mock connection to my database connection. It works fine when I run single test, but when I run multiple tests I receive the following exception:

Result StackTrace:  
at Effort.DbConnectionFactory.CreateTransient()
   at Tests.MyTest..ctor() 
----- Inner Stack Trace -----
   at Effort.Provider.EffortProviderConfiguration.RegisterDbConfigurationEventHandler()
   at Effort.Provider.EffortProviderConfiguration.RegisterProvider()
   at Effort.DbConnectionFactory..cctor()
----- Inner Stack Trace -----
   at System.Data.Entity.Infrastructure.DependencyResolution.DbConfigurationManager.AddLoadedHandler(EventHandler`1 handler)
   at System.Data.Entity.DbConfiguration.add_Loaded(EventHandler`1 value)
   at Effort.Provider.EffortProviderConfiguration.RegisterDbConfigurationEventHandler()
Result Message: 
System.TypeInitializationException : The type initializer for 'Effort.DbConnectionFactory' threw an exception.
---- Effort.Exceptions.EffortException : The Effort library failed to register its provider automatically, so manual registration is required.

a) Call the Effort.Provider.EffortProviderConfiguration.RegisterProvider() method at entry point of the application

or

b) Add the following configuration to the App.config file:
   <system.data>
      <DbProviderFactories>
         <add name="Effort.Provider"
              invariant="Effort.Provider"
              description="Effort.Provider"
              type="Effort.Provider.EffortProviderFactory, Effort" />
      </DbProviderFactories>
   </system.data>


   <entityFramework>
      <providers>
         <provider invariantName="Effort.Provider"
                   type="Effort.Provider.EffortProviderServices, Effort" />
      </providers>
   </entityFramework>
-------- System.InvalidOperationException : The Entity Framework was already using a DbConfiguration instance before an attempt was made to add an 'Loaded' event handler. 'Loaded' event handlers can only be added as part of application start up before the Entity Framework is used. See http://go.microsoft.com/fwlink/?LinkId=260883 for more information.

I have added mentioned configuration to app.config but it doesn't work. I can't add RegisterProvides() because I'm using xunit.net and it doesn't provide me any entry point.

Below is my code from MyTest constructor:

var connection = DbConnectionFactory.CreateTransient();
var context = new Mock<PaymentTransactionsDbContext>(connection, true);
@Terebi42
Copy link

I am having the exact same issue. vs2015, mstest

@tamasflamich
Copy link
Collaborator

Thank you for reporting this. It seems the problem is that the exception is still thrown when the xml configuration is set. As a workaround there should be an app config that disables this exception.

@darxis
Copy link

darxis commented Nov 15, 2016

Any workarounds? Still experiencing this issue...

@lukaszgulbinski
Copy link

lukaszgulbinski commented Jan 24, 2017

It happens to me when I use other provider in the same test project and a DbContext with this provider is initialized by test execution process before DbContext with Effort provider.

I have found few workarounds:

  1. Splitting test project into two different assemblies, one for testing with Effort, second for testing with real provider.
  2. Making sure that Effort.Provider.EffortProviderConfiguration.RegisterProvider(); is called before any test method which use DbContext with different provider (ex. [AssemblyInitializeAttribute]).

@reduckted
Copy link
Contributor

Despite having the provider specified in the app.config file, I was still getting this exception being thrown for my tests that were using Effort. I wasn't using any other provider in that assembly, so I couldn't understand why this exception was still being thrown.

tl;dr version
In one of my other tests I was creating a DbModelBuilder which results in the DbConfiguration being accessed and created. Once it's created, adding a handler to the Loaded event (which Effort does) will throw the exception we are seeing here.

Long Version
One of my tests creates a DbModelBuilder. This has the following call chain:

DbModelBuilder.ctor()
|-- DbModelBuilder.SelectConventionSet()
    |-- V1ConventionSet.cctor()
        |-- NotMappedTypeAttributeConvention.ctor()
            |-- TypeAttributeConfigurationConvention.ctor()
                |-- DbConfiguration.DependencyResolver
                    |-- InternalConfiguration.Instance
                        |-- InternalConfiguration.GetConfiguration() <-- This creates the configuration!!!

Once the configuration has been created, trying to add a handler to the DbConfiguration.Loaded event will throw an exception. Effort tries to add a handler for that event when it is first used.

I managed to work out which test was causing the configuration to be created by adding my own handler to the DbConfiguration.Loaded event and checking the call stack when that event is raised. The call stack should show you what test caused the event to be raised.

Since adding the event handler can throw an exception, I had to add it to the start of every test. I just created a method and called it at the start of every test.

void TrackLoaded() {
    DbConfiguration.Loaded += delegate(object sender, DbConfigurationLoadedEventArgs e) {
            System.Diagnostics.Debugger.Break();
        };
}

Then I just debugged all my tests (Test->Debug->All Tests). Once I worked out what test was causing the Loaded event to fire, I just added Effort.Provider.EffortProviderConfiguration.RegisterProvider() at the start of that test, and now all of the tests run without a problem!

@millerscout
Copy link

@reduckted you're right, i had a small project and i did mock a context and was doing some tests on that scenario, after you pointed this out, i could fix this problem as well, thanks.

@JamesIlling
Copy link

Is there a way to use EFFORT with an existing DataContextConfiguration? If so how.

@Terebi42
Copy link

@JamesIlling This probably isn't the right location for a question like this, this isn't a general purpose forum. But assuming your context class has the overload exposed which accepts a connection, the following will work

var connection = Effort.DbConnectionFactory.CreateTransient();
var context = new MyContext( connection, null );

@PhilHardingRiver
Copy link

I have the same issue except it only happens on the build server. The tests run perfectly on my local machine. None of the solutions I have read up on work for me. Any ideas why tests won't run on a second environment?

@GPRogers
Copy link

GPRogers commented May 2, 2019

Now that xUnit.NET 2.0 is released, the solution is

  • to implement your own subclass of XunitTestFramework,

  • Do your initialization in the constructor

  • Mark the assembly with a TestFrameworkAttribute.

EG:

using Xunit.Abstractions;
using Xunit.Sdk;

[assembly: Xunit.TestFramework("MyNamespace.MyClassName", "MyAssemblyName")]

namespace MyNamespace
{
    public class MyClassName : XunitTestFramework
    {
        public MyClassName(IMessageSink messageSink) : base(messageSink)
        {
            Effort.Provider.EffortProviderConfiguration.RegisterProvider();
        }
    }
}

@dotcom9
Copy link

dotcom9 commented Aug 6, 2019

Now that xUnit.NET 2.0 is released, the solution is

to implement your own subclass of XunitTestFramework,

Do your initialization in the constructor

Mark the assembly with a TestFrameworkAttribute.

EG:
using Xunit.Abstractions;
using Xunit.Sdk;

[assembly: Xunit.TestFramework("MyNamespace.MyClassName", "MyAssemblyName")]

namespace MyNamespace
{
public class MyClassName : XunitTestFramework
{
public MyClassName(IMessageSink messageSink) : base(messageSink)
{
Effort.Provider.EffortProviderConfiguration.RegisterProvider();
}
}
}

Thanks, a solution to this at last! I was intermittently getting the same error when running unit tests in a TeamCity build, though the tests worked fine in Visual Studio.

@StefH
Copy link

StefH commented Aug 23, 2019

@GPRogers & @dotcom9 What is the solution for NUnit?

@JonathanMagnan JonathanMagnan self-assigned this Oct 3, 2019
@vincentw56
Copy link

vincentw56 commented Oct 16, 2019

I was having this issue too in NUnit and this is what I did. I created a class file in the test project.

    [SetUpFixture]
    public class TestSetUpClass
    {
        [OneTimeSetUp]
        public void RunBeforeAnyTests()
        {
            Effort.Provider.EffortProviderConfiguration.RegisterProvider();
        }

        [OneTimeTearDown]
        public void RunAfterAnyTests()
        {
        }
    }

The project will see this file and run it before it starts the tests.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Development

No branches or pull requests