I'm testing some code that does work whenever assemblies are loaded into an appdomain. For unit testing (in VS2k8's built-in test host) I spin up a new, uniquely-named appdomain prior to each test with the idea that it should be "clean":
[TestInitialize()]
public void CalledBeforeEachTestMethod()
{
AppDomainSetup appSetup = new AppDomainSetup();
appSetup.ApplicationBase = #"G:\<ProjectDir>\bin\Debug";
Evidence baseEvidence = AppDomain.CurrentDomain.Evidence;
Evidence evidence = new Evidence( baseEvidence );
_testAppDomain = AppDomain.CreateDomain( "myAppDomain" + _appDomainCounter++, evidence, appSetup );
}
[TestMethod]
public void MissingFactoryCausesAppDomainUnload()
{
SupportingClass supportClassObj = (SupportingClass)_testAppDomain.CreateInstanceAndUnwrap(
GetType().Assembly.GetName().Name,
typeof( SupportingClass ).FullName );
try
{
supportClassObj.LoadMissingRegistrationAssembly();
Assert.Fail( "Should have nuked the app domain" );
}
catch( AppDomainUnloadedException ) { }
}
[TestMethod]
public void InvalidFactoryMethodCausesAppDomainUnload()
{
SupportingClass supportClassObj = (SupportingClass)_testAppDomain.CreateInstanceAndUnwrap(
GetType().Assembly.GetName().Name,
typeof( SupportingClass ).FullName );
try
{
supportClassObj.LoadInvalidFactoriesAssembly();
Assert.Fail( "Should have nuked the app domain" );
}
catch( AppDomainUnloadedException ) { }
}
public class SupportingClass : MarshalByRefObject
{
public void LoadMissingRegistrationAssembly()
{
MissingRegistration.Main();
}
public void LoadInvalidFactoriesAssembly()
{
InvalidFactories.Main();
}
}
If every test is run individually I find that it works correctly; the appdomain is created and has only the few intended assemblies loaded. However, if multiple tests are run in succession then each _testAppDomain already has assemblies loaded from all previous tests. Oddly enough, the two tests get appdomains with different names. The test assemblies that define MissingRegistration and InvalidFactories (two different assemblies) are never loaded into the unit test's default appdomain. Can anyone explain this behavior?
It sounds like what's is happening is that the assemblies are getting loaded in the parent AppDomain. If so, your bug is in the details of how you use are using _testAppDomain elsewhere in your test code, now how you create it.
Ideally test harness code should run itself in the AppDomain, and then the method running in the AppDomain should do the actual loading of the assemblies under test.
Here is an example to give the idea of how to keep the parent AppDomain from ever loading your test assemblies:
void TestRunner()
{
testProxy =
(TestProxy)_testAppDomain.CreateInstanceAndUnwrap(
typeof(TestProxy).Assembly.FullName,
typeof(TestProxy).FullName)
testProxy.RunTest(testAssembly, typeName);
}
public class TestProxy : MarshalByRefObject
{
public void Runtest(string testAssembly, string typeName)
{
var testType = Assembly.Load(testAssembly).GetType(typeName);
// run tests in testType using reflection or whatever
}
}
In your particular situation, however, it may be that you don't really have any test assemblies per se, so maybe this doesn't apply.
I also noticed that your [TestInitialize] comment says it is called once per test, but IIRC, the docs say Visual Studio's test framework only calls this once per class when it is running multiple tests. I use a different framework, so I am not sure of this.
Update
Now that I can see the rest of your code, I can see you already are taking reasonable precautions not to load assemblies in the parent AppDomain. You say that is indeed not happening, and I believe you. If worse comes to worse, you could try having your SupportingClass call another assembly which then does your test, but I don't really think this would change anything.
I do have another theory for you:
I read somewhere (on a blog, I think) that JITed methods are cached and reused between AppDomains based on a signature that includes some of the assembly load rules. I assume this would include ApplicationBase.
So my theory is that when NET Framework loads your assembly (or maybe when it loads your SupportingClass), it is scanning for already-JITed methods it can use. When it finds the previously JITed method it "enables" it (for lack of a better word) in that AppDomain, which triggers a load of assembly it depends on.
This would explain why changin ApplicationBase makes it work: The JITed methods would not be reused from the cache, and since the method is never called it is not JITed again so the dependent assembly is never loaded.
It seems to me that you have a good workaround in varying the ApplicationBase, or you might try varying the Evidence if the ApplicationBase is important to keep the same. I would think this would have the same effect.
Related
There is a singleton service class ItemsDataSource: IItemsDataSource injected into many other classes (business domain classes)
These business domain classes are many and run asynchronously calling methods on that ItemsDataSource service.
public interface IItemsDataSource
{
Task<IEnumerable<string>> GetItemsAsync();
void SetSourceConfiguration(JToken src);
}
public class ItemsDataSource : IItemsDataSource
{
private JToken m_configuration;
public Task<IEnumerable<string>> GetItemsAsync()
{
// Use m_configuration to some items
}
public void SetSourceConfiguration(JToken config)
{
m_configuration = src;
}
}
When multiple classes that are using this service are running asynchronously (let's say on 2 threads T1 and T2), this is sometimes happening:
T1 calls SetSourceConfiguration(config1) then starts running GetItemsAsync() asynchronously.
T2 calls SetSourceConfiguration(config2) (m_configuration is now assigned with config2) before T1 is done running GetItemsAsync(). For that T1 uses config2 instead of config1 and unexpected behavior happens.
The questions:
1- The optimal fix I think is removing SetSourceConfiguration and passing the JToken config directly as parameter into GetItemsAsync, or locking the code in the business classes, or is there another better solution ?
2- Which design pattern violation caused this bug ? So It could be avoided in the first place.
3- What is the "technical" term for this bug ? Methods with Side Effects, Design pattern violation, etc. ?
1- The optimal fix I think is removing SetSourceConfiguration and
passing the JToken config directly as parameter into GetItemsAsync, or
locking the code in the business classes, or is there another better
solution ?
If your service ItemsDataSource is not singleton service, you can remove SetSourceConfiguration and passing the JToken config directly as parameter into GetItemsAsync. However, it is singleton service, so the way to go, imho, is using lock of critical section.
The code would look like this, if you are using C#.
private readonly object myLock = new object();
public void Foo()
{
lock (myLock )
{
// critical section of code here
}
}
Read more about lock here
2- Which design pattern violation caused this bug ? So It could be
avoided in the first place.
It is not pattern. It is race condition. A race condition occurs when two or more threads can access shared data and they try to change it at the same time.
3- What is the "technical" term for this bug ? Methods with Side
Effects, Design pattern violation, etc. ?
It is race condition.
I am using xUnit for integration testing. and for that, I use a localdb instance for it. With that being said, I would like to initiate DB instance once with some pre-defined data and of course I would that stay true for all test cases. I could write each test cases isolated so they are not running into each other however I would like to only create DB instance once.
I followed xunit constructor runs before each test and the code looks like
//similar to base class
public class DatabaseFixture : IDisposable
{
public SqlConnection Db { get; private set; }
public DatabaseFixture()
{
InitialDB();
}
public InitialDB()
{
CreateDBInstance();
CreateDBSchemas();
InitDBMetaData();
}
public void Dispose()
{
// clean up test data from the database
CleanUpDB();
}
}
//Class where you want to use shared class instance
public class MyDatabaseTests : IClassFixture<DatabaseFixture>
{
DatabaseFixture dbFixture;
public MyDatabaseTests(DatabaseFixture fixture)
{
this.dbFixture = fixture;
}
// write tests, using dbFixture.Db to get access to the SQL Server
}
The problem I am facing is I noticed this DBFixture being called everytime per test case. I thought with iClassFixture it is only called once. which brings problem when test cases run in parallel because it is trying to cleanup db while other test trying to access it and also multiple test cases would try to create the db at the same time which causes error. https://xunit.net/docs/shared-context.html
Can anyone shed light on why it is not working?
I stumbled across the same problem and it was an issue with visual studio:
https://github.com/xunit/xunit/issues/2347#issuecomment-983586580
Right clicking the class file which contains the tests to start the test runner, may lead to this behaviour.
You need to use Collection Fixtures instead.
https://xunit.net/docs/shared-context#collection-fixture
When to use: when you want to create a single test context and share it among tests in several test classes, and have it cleaned up after all the tests in the test classes have finished.
I am having a hard-time implementing the workaround to the problem with disposing Cache mentioned in this thread MemoryCache Empty : Returns null after being set.
My latest attempt has the following code to get an instance, wrapped as suggested, in a using statement to suppress the cache from being disposed:
private static CacheDl _instance;
public static CacheDl Instance
{
get
{
if (_instance == null)
{
using (ExecutionContext.SuppressFlow())
{
_instance = new CacheDl();
}
}
return _instance;
}
}
private static ObjectCache Cache { get { return MemoryCache.Default; } }
Of course this doesn't work.. I have also tried wrapping the Cache 'getter' in something similar but still no deal.
I have also tried specifying a large pollingInterval to suppress the behavior altogether and still no success.
private ObjectCache _cache;
private ObjectCache Cache
{
get
{
using (ExecutionContext.SuppressFlow())
{
return _cache ?? (_cache = new MemoryCache("my-cache", new NameValueCollection { { "pollingInterval", "30:00:00" } }));
}
}
}
You guessed it, no luck. Any help would be greatly appreciated.
By the way, I have already requested the mentioned Fixpack from Microsoft but not yet heard anything back after 4 hours having submitted the request..
Honestly, I would really prefer that this would be rolled up into an official Windows Update so we wouldn't have to hack around to get this working on non-.NET 4.5 systems.
Update:
Specifically, I would like to know how I am meant to implement the recommended work-around. Can someone please show an example of how this can be implemented?
I am working on this same problem. In my case the problem seems to be the cache is disposed on the AppDomain's UnhandledException event. See the source snippet of MemoryCache here.
As you can see, it disposes itself. My solution is to wrap my cache access in a class that can subscribe to this event and initialize a new cache when the old one gets disposed. This solution seems to work for me but it does feel rather hack-y.
The cache will still be cleared unexpectedly on the UnhandledException event, but at least this way you are able to start over using a new cache.
public class MyCacheWrapper
{
private MemoryCache cache;
public MyCacheWrapper()
{
cache = new MemoryCache("settings");
AppDomain.CurrentDomain.UnhandledException += (sender, args) =>
{
if(args.IsTerminating)
cache = new MemoryCache("settings");
};
}
}
Note also that you can also use this class to dispose and recreate the cache when you wish to clear it, because MemoryCache's Trim() method does not work properly.
Ended up sorting this out with configuration settings to extend the Cache polling interval sufficient enough that the application pool will recycle before the interval is reached. Had tried doing this in code when constructing a Cache instance but that didn't work out..
A comment on the relevant Connect issue mentions this as workable hack if you can control your application pool, while another mentions this on the social.msdn forum.
Connect Issue
social.msdn
The configuration setting which increases the polling interval by 30 hours:
<system.runtime.caching>
<memoryCache>
<namedCaches>
<add name="Default"
cacheMemoryLimitMegabytes="0"
physicalMemoryLimitPercentage="0"
pollingInterval="30:00:00" />
</namedCaches>
</memoryCache>
</system.runtime.caching>
I'm in the middle of a significant effort to introduce NHibernate into our code base. I figured I would have to use some kind of a DI container, so I can inject dependencies into the entities I load from the database. I chose Unity as that container.
I'm considering using Unity's interception mechanism to add a transaction aspect to my code, so I can do e.g. the following:
class SomeService
{
[Transaction]
public void DoSomething(CustomerId id)
{
Customer c = CustomerRepository.LoadCustomer(id);
c.DoSomething();
}
}
and the [Transaction] handler will take care of creating a session and a transaction, committing the transaction (or rolling back on exception), etc.
I'm concerned that using this kind of interception will bind me to using Unity pretty much everywhere in the code. If I introduce aspects in this manner, then I must never, ever call new SomeService(), or I will get a service that doesn't have transactions. While this is acceptable in production code, it seems too much overhead in tests. For example, I would have to convert this:
void TestMethod()
{
MockDependency dependency = new MockDependency();
dependency.SetupForTest();
var service = SomeService(dependency);
service.DoSomething();
}
into this:
void TestMethod()
{
unityContainer.RegisterType<MockDependency>();
unityContainer.RegisterType<IDependency, MockDependency>();
MockDependency dependency = unityContainer.Resolve<MockDependency>();
dependency.SetupForTest();
var service = unityContainer.Resolve<SomeService>();
service.DoSomething();
}
This adds 2 lines for each mock object that I'm using, which leads to quite a bit of code (our tests use a lot of stateful mocks, so it is not uncommon for a test class to have 5-8 mock objects, and sometimes more.)
I don't think standalone injection would help here: I have to set up injection for every class that I use in the tests, because it's possible for aspects to be added to a class after the test is written.
Now, if I drop the use of interception I'll end up with:
class SomeService
{
public void DoSomething(CustomerId id)
{
Transaction.Run(
() => {
Customer c = CustomerRepository.LoadCustomer(id);
c.DoSomething();
});
}
}
which is admittedly not as nice, but doesn't seem that bad either.
I can even set up my own poor man's interception:
class SomeService
{
[Transaction]
public void DoSomething(CustomerId id)
{
Interceptor.Intercept(
MethodInfo.GetCurrentMethod(),
() => {
Customer c = CustomerRepository.LoadCustomer(id);
c.DoSomething();
});
}
}
and then my interceptor can process the attributes for the class, but I can still instantiate the class using new and not worry about losing functionality.
Is there a better way of using Unity interception, that doesn't force me to always use it for instantiating my objects?
If you want to use AOP but are concerned abut Unity then I would recommend you check out PostSharp. That implements AOP as a post-compile check but has no changes on how you use the code at runtime.
http://www.sharpcrafters.com/
They have a free community edition that has a good feature set, as well as professional and enterprise versions that have significantly enhanced feature sets.
Based on this article, I've written a custom class which implements the Watin.Core.interfaces.IFindByDefaultFactory, but I don't think I'm correctly assigning it to the watin settings, because it is never used.
Basically, Where/when should I assign to the Settings.FindByDefaultFactory? I've tried in my test Setup, and the text fixture's constructor, but neither seem to cause my custom class to be used. The tests still run and work, but I have to use the full asp.net ID's.
I'm using Watin 2.0.15.928 in VS2008 from nUnit 2.5.2.9222. I am running visual studio as administrator, and tests run sucessfully as long as I don't rely on my custom find logic.
Here's what the start of my text fixture looks like, where I set the FindByDefaultFactory
namespace Fundsmith.Web.Main.BrowserTests
{
[TestFixture]
class WatinHomepageTests
{
private IE _ie;
[SetUp]
public void Setup()
{
Settings.FindByDefaultFactory = new FindByAspIdFactory();
_ie = new IE("http://localhost/somepage.aspx");
}
//etc etc...
And this is what my custom Find By Default factory looks like (simplified), unfortunately, it's never called.
using System.Text.RegularExpressions;
using WatiN.Core;
using WatiN.Core.Constraints;
using WatiN.Core.Interfaces;
namespace Fundsmith.Web.Main.BrowserTests
{
public class FindByAspIdFactory : IFindByDefaultFactory
{
public Constraint ByDefault(string value)
{
// This code is never called :(
// My custom find by id code to cope with asp.net webforms ids...
return Find.ById(value);
}
public Constraint ByDefault(Regex value)
{
return Find.ById(value);
}
}
}
Edit: Extra information after the fact.
Based on me fuguring this out, (see answer below), It turns out that the way I was consuming Watin to find the elements was wrong. I was explicitly calling Find.ById, rather than letting the default action occur. So I'd reassigned the default but was then failing to use it!
[Test]
public void StepOneFromHomepageShouldRedirectToStepTwo()
{
_ie.TextField(Find.ById("textBoxId")).TypeText("100");
//Other test stuff...
}
Right, I've figured this one out, and it was me being an idiot and explicitly calling the Find.ById method, rather than letting the default action occur. It seems the test setup is a fine place to set the FindByDefaultFactory.
ie, I was doing this (wrong):
[Test]
public void StepOneFromHomepageShouldRedirectToStepTwo()
{
_ie.TextField(Find.ById("textBoxId")).TypeText("100");
//Other test stuff...
}
When I should have been simply doing this. (Without the explicit "Find.ById")
[Test]
public void StepOneFromHomepageShouldRedirectToStepTwo()
{
_ie.TextField("textBoxId").TypeText("100");
//Other test stuff...
}
Not only was this me being stupid, but I didn't include this in my original question, so it would have been impossible for anyone else to figure it out for certain. Double slaps for me.