diff --git a/src/Spring/Spring.Testing.Microsoft/AssemblyInfo.cs b/src/Spring/Spring.Testing.Microsoft/AssemblyInfo.cs
new file mode 100644
index 00000000..1fa90498
--- /dev/null
+++ b/src/Spring/Spring.Testing.Microsoft/AssemblyInfo.cs
@@ -0,0 +1,5 @@
+using System;
+using System.Reflection;
+
+[assembly: AssemblyTitle("Spring.Testing.Microsoft")]
+[assembly: AssemblyDescription("Interfaces and classes that provide Microsoft Unit Testing integration in Spring.Net")]
\ No newline at end of file
diff --git a/src/Spring/Spring.Testing.Microsoft/Spring.Testing.Microsoft.2008.csproj b/src/Spring/Spring.Testing.Microsoft/Spring.Testing.Microsoft.2008.csproj
new file mode 100644
index 00000000..98da2659
--- /dev/null
+++ b/src/Spring/Spring.Testing.Microsoft/Spring.Testing.Microsoft.2008.csproj
@@ -0,0 +1,115 @@
+
+
+ Debug
+ AnyCPU
+ 9.0.30729
+ 2.0
+ {2E10A8D3-B8FF-4699-90B8-E621659C58DD}
+ Library
+ Properties
+ Spring
+ Spring.Testing.Microsoft
+
+
+ 2.0
+
+
+ http://localhost/Spring.Testing.Microsoft/
+ true
+ Web
+ true
+ Foreground
+ 7
+ Days
+ false
+ false
+ true
+ 0
+ 1.0.0.%2a
+ true
+ false
+ true
+
+
+ true
+ full
+ false
+ ..\..\..\build\VS.NET.2005\Spring.Testing.Microsoft\Debug\
+ TRACE;DEBUG;NET_2_0
+ prompt
+ 4
+ ..\..\..\build\VS.NET.2005\Spring.Testing.Microsoft\Debug\Spring.Testing.Microsoft.xml
+
+
+ pdbonly
+ true
+ ..\..\..\build\VS.NET.2005\Spring.Testing.Microsoft\Release\
+ TRACE;NET_2_0
+ prompt
+ 4
+
+
+
+ False
+ ..\..\..\lib\net\2.0\Common.Logging.dll
+
+
+
+
+
+
+
+ CommonAssemblyInfo.cs
+
+
+
+
+
+
+
+
+
+ False
+ .NET Framework Client Profile
+ false
+
+
+ False
+ .NET Framework 2.0 %28x86%29
+ true
+
+
+ False
+ .NET Framework 3.0 %28x86%29
+ false
+
+
+ False
+ .NET Framework 3.5
+ false
+
+
+ False
+ .NET Framework 3.5 SP1
+ false
+
+
+
+
+ {710961A3-0DF4-49E4-A26E-F5B9C044AC84}
+ Spring.Core.2008
+
+
+ {AE00E5AB-C39A-436F-86D2-33BFE33E2E40}
+ Spring.Data.2008
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Spring/Spring.Testing.Microsoft/Testing/Microsoft/AbstractDependencyInjectionSpringContextTests.cs b/src/Spring/Spring.Testing.Microsoft/Testing/Microsoft/AbstractDependencyInjectionSpringContextTests.cs
new file mode 100644
index 00000000..372eabd2
--- /dev/null
+++ b/src/Spring/Spring.Testing.Microsoft/Testing/Microsoft/AbstractDependencyInjectionSpringContextTests.cs
@@ -0,0 +1,370 @@
+#region License
+
+/*
+/// Copyright 2002-2006 the original author or authors.
+///
+/// Licensed under the Apache License, Version 2.0 (the "License");
+/// you may not use this file except in compliance with the License.
+/// You may obtain a copy of the License at
+///
+/// http://www.apache.org/licenses/LICENSE-2.0
+///
+/// Unless required by applicable law or agreed to in writing, software
+/// distributed under the License is distributed on an "AS IS" BASIS,
+/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+/// See the License for the specific language governing permissions and
+/// limitations under the License.
+ */
+
+#endregion
+
+using System;
+using System.Collections;
+using System.Reflection;
+
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+using Spring.Context;
+using Spring.Context.Support;
+using Spring.Objects.Factory;
+using Spring.Objects.Factory.Config;
+using Spring.Objects.Factory.Support;
+
+namespace Spring.Testing.Microsoft
+{
+ ///
+ /// Convenient superclass for tests depending on a Spring context.
+ /// The test instance itself is populated by Dependency Injection.
+ ///
+ ///
+ ///
+ ///
Really for integration testing, not unit testing.
+ /// You should not normally use the Spring container
+ /// for unit tests: simply populate your objects in plain NUnit tests!
+ ///
+ ///
This supports two modes of populating the test:
+ ///
+ ///
Via Property Dependency Injection. Simply express dependencies on objects
+ /// in the test fixture, and they will be satisfied by autowiring by type.
+ ///
Via Field Injection. Declare protected variables of the required type
+ /// which match named beans in the context. This is autowire by name,
+ /// rather than type. This approach is based on an approach originated by
+ /// Ara Abrahmian. Property Dependency Injection is the default: set the
+ /// "populateProtectedVariables" property to true in the constructor to switch
+ /// on Field Injection.
+ ///
+ ///
+ ///
This class will normally cache contexts based on a context key:
+ /// normally the config locations String array describing the Spring resource
+ /// descriptors making up the context. Unless the SetDirty() method
+ /// is called by a test, the context will not be reloaded, even across different
+ /// subclasses of this test. This is particularly beneficial if your context is
+ /// slow to construct, for example if you are using Hibernate and the time taken
+ /// to load the mappings is an issue.
+ ///
+ ///
If you don't want this behavior, you can override the ContextKey
+ /// property, most likely to return the test class. In conjunction with this you would
+ /// probably override the GetContext method, which by default loads
+ /// the locations specified by the ConfigLocations property.
+ ///
+ ///
WARNING: When doing integration tests from within VS.NET, only use
+ /// assembly resource URLs. Else, you may see misleading failures when changing
+ /// context locations.
+ ///
+ ///
+ /// Rod Johnson
+ /// Rob Harrop
+ /// Rick Evans
+ /// Aleksandar Seovic (.NET)
+ public abstract class AbstractDependencyInjectionSpringContextTests : AbstractSpringContextTests
+ {
+ private bool populateProtectedVariables = false;
+ private AutoWiringMode autowireMode = AutoWiringMode.ByType;
+ private bool dependencyCheck = true;
+
+ ///
+ /// Application context this test will run against.
+ ///
+ protected IConfigurableApplicationContext applicationContext;
+
+ ///
+ /// Holds names of the fields that should be used for field injection.
+ ///
+ protected string[] managedVariableNames;
+ private int loadCount = 0;
+
+ ///
+ /// Default constructor for AbstractDependencyInjectionSpringContextTests.
+ ///
+ public AbstractDependencyInjectionSpringContextTests()
+ {}
+
+ ///
+ /// Gets or sets a flag specifying whether to populate protected
+ /// variables of this test case.
+ ///
+ ///
+ /// A flag specifying whether to populate protected variables of this test case.
+ /// Default is false.
+ ///
+ public bool PopulateProtectedVariables
+ {
+ get { return populateProtectedVariables; }
+ set { populateProtectedVariables = value; }
+ }
+
+ ///
+ /// Gets or sets the autowire mode for test properties set by Dependency Injection.
+ ///
+ ///
+ /// The autowire mode for test properties set by Dependency Injection.
+ /// The default is .
+ ///
+ public AutoWiringMode AutowireMode
+ {
+ get { return autowireMode; }
+ set { autowireMode = value; }
+ }
+
+ ///
+ /// Gets or sets a flag specifying whether or not dependency checking
+ /// should be performed for test properties set by Dependency Injection.
+ ///
+ ///
+ ///
A flag specifying whether or not dependency checking
+ /// should be performed for test properties set by Dependency Injection.
+ ///
The default is true, meaning that tests cannot be run
+ /// unless all properties are populated.
+ ///
+ public bool DependencyCheck
+ {
+ get { return dependencyCheck; }
+ set { dependencyCheck = value; }
+ }
+
+ ///
+ /// Gets the current number of context load attempts.
+ ///
+ public int LoadCount
+ {
+ get { return loadCount; }
+ }
+
+ ///
+ /// Called to say that the "applicationContext" instance variable is dirty and
+ /// should be reloaded. We need to do this if a test has modified the context
+ /// (for example, by replacing an object definition).
+ ///
+ public void SetDirty()
+ {
+ SetDirty(ConfigLocations);
+ }
+
+ ///
+ /// Test setup method.
+ ///
+ [TestInitialize]
+ public virtual void TestInitialize()
+ {
+ this.applicationContext = GetContext(ContextKey);
+ InjectDependencies();
+ try
+ {
+ OnTestInitialize();
+ }
+ catch (Exception ex)
+ {
+ logger.Error("Setup error", ex);
+ throw;
+ }
+ }
+
+ ///
+ /// Inject dependencies into 'this' instance (that is, this test instance).
+ ///
+ ///
+ ///
The default implementation populates protected variables if the
+ /// property is set, else
+ /// uses autowiring if autowiring is switched on (which it is by default).
+ ///
You can certainly override this method if you want to totally control
+ /// how dependencies are injected into 'this' instance.
+ ///
+ protected virtual void InjectDependencies()
+ {
+ if (PopulateProtectedVariables)
+ {
+ if (this.managedVariableNames == null)
+ {
+ InitManagedVariableNames();
+ }
+ InjectProtectedVariables();
+ }
+ else if (AutowireMode != AutoWiringMode.No)
+ {
+ IConfigurableListableObjectFactory factory = this.applicationContext.ObjectFactory;
+ ((AbstractObjectFactory) factory).IgnoreDependencyType(typeof(AutoWiringMode));
+ factory.AutowireObjectProperties(this, AutowireMode, DependencyCheck);
+ }
+ }
+
+ ///
+ /// Gets a key for this context. Usually based on config locations, but
+ /// a subclass overriding buildContext() might want to return its class.
+ ///
+ protected virtual object ContextKey
+ {
+ get { return ConfigLocations; }
+ }
+
+ ///
+ /// Loads application context from the specified resource locations.
+ ///
+ /// Resources to load object definitions from.
+ protected override IConfigurableApplicationContext LoadContextLocations(string[] locations)
+ {
+ ++this.loadCount;
+ return base.LoadContextLocations(locations);
+ }
+
+ ///
+ /// Retrieves the names of the fields that should be used for field injection.
+ ///
+ protected virtual void InitManagedVariableNames()
+ {
+ ArrayList managedVarNames = new ArrayList();
+ Type type = GetType();
+
+ do
+ {
+ FieldInfo[] fields =
+ type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Instance);
+ if (logger.IsDebugEnabled)
+ {
+ logger.Debug("Found " + fields.Length + " fields on " + type);
+ }
+
+ for (int i = 0; i < fields.Length; i++)
+ {
+ FieldInfo field = fields[i];
+ if (logger.IsDebugEnabled)
+ {
+ logger.Debug("Candidate field: " + field);
+ }
+ if (IsProtectedInstanceField(field))
+ {
+ object oldValue = field.GetValue(this);
+ if (oldValue == null)
+ {
+ managedVarNames.Add(field.Name);
+ if (logger.IsDebugEnabled)
+ {
+ logger.Debug("Added managed variable '" + field.Name + "'");
+ }
+ }
+ else
+ {
+ if (logger.IsDebugEnabled)
+ {
+ logger.Debug("Rejected managed variable '" + field.Name + "'");
+ }
+ }
+ }
+ }
+ type = type.BaseType;
+ } while (type != typeof (AbstractDependencyInjectionSpringContextTests));
+
+ this.managedVariableNames = (string[]) managedVarNames.ToArray(typeof (string));
+ }
+
+ private static bool IsProtectedInstanceField(FieldInfo field)
+ {
+ return field.IsFamily;
+ }
+
+ ///
+ /// Injects protected fields using Field Injection.
+ ///
+ protected virtual void InjectProtectedVariables()
+ {
+ for (int i = 0; i < this.managedVariableNames.Length; i++)
+ {
+ string fieldName = this.managedVariableNames[i];
+ Object obj = null;
+ try
+ {
+ FieldInfo field = GetType().GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance);
+ if (field != null)
+ {
+ BeforeProtectedVariableInjection(field);
+ obj = this.applicationContext.GetObject(fieldName, field.FieldType);
+ field.SetValue(this, obj);
+ if (logger.IsDebugEnabled)
+ {
+ logger.Debug("Populated field: " + field);
+ }
+ }
+ else
+ {
+ if (logger.IsWarnEnabled)
+ {
+ logger.Warn("No field with name '" + fieldName + "'");
+ }
+ }
+ }
+ catch (NoSuchObjectDefinitionException)
+ {
+ if (logger.IsWarnEnabled)
+ {
+ logger.Warn("No object definition with name '" + fieldName + "'");
+ }
+ }
+ }
+ }
+
+ ///
+ /// Called right before a field is being injected
+ ///
+ protected virtual void BeforeProtectedVariableInjection(FieldInfo fieldInfo)
+ {
+
+ }
+
+ ///
+ /// Subclasses can override this method in order to
+ /// add custom test setup logic.
+ ///
+ protected virtual void OnTestInitialize()
+ {}
+
+ ///
+ /// Test teardown method.
+ ///
+ [TestCleanup]
+ public void TestCleanup()
+ {
+ try
+ {
+ OnTestCleanup();
+ }
+ catch (Exception ex)
+ {
+ logger.Error("OnTearDown error", ex);
+ }
+ }
+
+ ///
+ /// Subclasses can override this method in order to
+ /// add custom test teardown logic.
+ ///
+ protected virtual void OnTestCleanup()
+ {}
+
+
+ ///
+ /// Subclasses must implement this property to return the locations of their
+ /// config files. A plain path will be treated as a file system location.
+ ///
+ /// An array of config locations
+ protected abstract string[] ConfigLocations { get; }
+ }
+}
\ No newline at end of file
diff --git a/src/Spring/Spring.Testing.Microsoft/Testing/Microsoft/AbstractSpringContextTests.cs b/src/Spring/Spring.Testing.Microsoft/Testing/Microsoft/AbstractSpringContextTests.cs
new file mode 100644
index 00000000..9c86e6d6
--- /dev/null
+++ b/src/Spring/Spring.Testing.Microsoft/Testing/Microsoft/AbstractSpringContextTests.cs
@@ -0,0 +1,238 @@
+#region License
+
+/*
+ * Copyright 2002-2009 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#endregion
+
+using System;
+using System.Collections;
+using Common.Logging;
+using Spring.Context;
+using Spring.Context.Support;
+using Spring.Util;
+
+namespace Spring.Testing.Microsoft
+{
+ ///
+ /// Superclass for NUnit test cases using a Spring context.
+ ///
+ ///
+ ///
Maintains a cache of contexts by key. This has significant performance
+ /// benefit if initializing the context would take time. While initializing a
+ /// Spring context itself is very quick, some objects in a context, such as
+ /// a LocalSessionFactoryObject for working with NHibernate, may take time to
+ /// initialize. Hence it often makes sense to do that initializing once.
+ ///
Normally you won't extend this class directly but rather extend one
+ /// of its subclasses.
+ ///
+ /// Rod Johnson
+ /// Aleksandar Seovic (.NET)
+ public abstract class AbstractSpringContextTests
+ {
+ ///
+ /// Map of context keys returned by subclasses of this class, to
+ /// Spring contexts.
+ ///
+ private static readonly IDictionary contextKeyToContextMap;
+
+ ///
+ /// Static ctor to avoid "beforeFieldInit" problem.
+ ///
+ static AbstractSpringContextTests()
+ {
+ contextKeyToContextMap = new Hashtable();
+ }
+
+ ///
+ /// Disposes any cached context instance and removes it from cache.
+ ///
+ public static void ClearContextCache()
+ {
+ foreach(IApplicationContext ctx in contextKeyToContextMap.Values)
+ {
+ ctx.Dispose();
+ }
+ contextKeyToContextMap.Clear();
+ }
+
+ ///
+ /// Indicates, whether context instances should be automatically registered with the global .
+ ///
+ private bool registerContextWithContextRegistry = true;
+
+ ///
+ /// Logger available to subclasses.
+ ///
+ protected readonly ILog logger;
+
+ ///
+ /// Default constructor for AbstractSpringContextTests.
+ ///
+ protected AbstractSpringContextTests()
+ {
+ logger = LogManager.GetLogger(GetType());
+ }
+
+ ///
+ /// Controls, whether application context instances will
+ /// be registered/unregistered with the global .
+ /// Defaults to true.
+ ///
+ public bool RegisterContextWithContextRegistry
+ {
+ get { return registerContextWithContextRegistry; }
+ set { registerContextWithContextRegistry = value; }
+ }
+
+ ///
+ /// Set custom locations dirty. This will cause them to be reloaded
+ /// from the cache before the next test case is executed.
+ ///
+ ///
+ /// Call this method only if you change the state of a singleton
+ /// object, potentially affecting future tests.
+ ///
+ /// Locations
+ protected void SetDirty(string[] locations)
+ {
+ String keyString = ContextKeyString(locations);
+ IConfigurableApplicationContext ctx =
+ (IConfigurableApplicationContext) contextKeyToContextMap[keyString];
+ contextKeyToContextMap.Remove(keyString);
+
+ if (ctx != null)
+ {
+ ctx.Dispose();
+ }
+ }
+
+ ///
+ /// Returns true if context for the specified
+ /// is cached.
+ ///
+ /// Context key to check.
+ ///
+ /// true if context for the specified
+ /// is cached,
+ /// false otherwise.
+ ///
+ protected bool HasCachedContext(object contextKey)
+ {
+ string keyString = ContextKeyString(contextKey);
+ return contextKeyToContextMap.Contains(keyString);
+ }
+
+ ///
+ /// Converts context key to string.
+ ///
+ ///
+ /// Subclasses can override this to return a string representation of
+ /// their contextKey for use in logging.
+ ///
+ /// Context key to convert.
+ ///
+ /// String representation of the specified . Null if
+ /// contextKey is null.
+ ///
+ protected virtual string ContextKeyString(object contextKey)
+ {
+ if (contextKey == null)
+ {
+ return null;
+ }
+ if (contextKey is string[])
+ {
+ return StringUtils.ArrayToCommaDelimitedString((string[]) contextKey);
+ }
+ else
+ {
+ return contextKey.ToString();
+ }
+ }
+
+ ///
+ /// Caches application context.
+ ///
+ /// Key to use.
+ /// Context to cache.
+ public void AddContext(object key, IConfigurableApplicationContext context)
+ {
+ AssertUtils.ArgumentNotNull(context, "context", "ApplicationContext must not be null");
+ string keyString = ContextKeyString(key);
+ contextKeyToContextMap.Add(keyString, context);
+
+ if (RegisterContextWithContextRegistry
+ && !ContextRegistry.IsContextRegistered(context.Name))
+ {
+ ContextRegistry.RegisterContext(context);
+ }
+ }
+
+ ///
+ /// Returns cached context if present, or loads it if not.
+ ///
+ /// Context key.
+ /// Spring application context associated with the specified key.
+ protected IConfigurableApplicationContext GetContext(object key)
+ {
+ string keyString = ContextKeyString(key);
+ IConfigurableApplicationContext ctx =
+ (IConfigurableApplicationContext) contextKeyToContextMap[keyString];
+ if (ctx == null)
+ {
+ if (key is string[])
+ {
+ ctx = LoadContextLocations((string[]) key);
+ }
+ else
+ {
+ ctx = LoadContext(key);
+ }
+ AddContext(key, ctx);
+ }
+ return ctx;
+ }
+
+
+ ///
+ /// Loads application context from the specified resource locations.
+ ///
+ /// Resources to load object definitions from.
+ protected virtual IConfigurableApplicationContext LoadContextLocations(string[] locations)
+ {
+ if (logger.IsInfoEnabled)
+ {
+ logger.Info("Loading config for: " + StringUtils.ArrayToCommaDelimitedString(locations));
+ }
+ return new XmlApplicationContext(locations);
+ }
+
+ ///
+ /// Loads application context based on user-defined key.
+ ///
+ ///
+ /// Unless overriden by the user, this method will alway throw
+ /// a .
+ ///
+ /// User-defined key.
+ protected virtual IConfigurableApplicationContext LoadContext(object key)
+ {
+ throw new NotSupportedException("Subclasses may override this");
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/Spring/Spring.Testing.Microsoft/Testing/Microsoft/AbstractTransactionalDbProviderSpringContextTests.cs b/src/Spring/Spring.Testing.Microsoft/Testing/Microsoft/AbstractTransactionalDbProviderSpringContextTests.cs
new file mode 100644
index 00000000..eb2e32d8
--- /dev/null
+++ b/src/Spring/Spring.Testing.Microsoft/Testing/Microsoft/AbstractTransactionalDbProviderSpringContextTests.cs
@@ -0,0 +1,125 @@
+#region License
+
+/*
+ * Copyright 2002-2009 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#endregion
+
+
+using System;
+using System.Data;
+using Spring.Data.Common;
+using Spring.Data.Core;
+
+namespace Spring.Testing.Microsoft
+{
+ ///
+ /// Subclass of AbstractTransactionalSpringContextTests that adds some convenience
+ /// functionality for ADO.NET access. Expects a IDbProvider object
+ /// to be defined in the Spring application context.
+ ///
+ ///
+ /// This class exposes a AdoTemplate and provides an easy way to delete from the
+ /// database in a new transaction.
+ ///
+ /// Rod Johnson
+ /// Juergen Hoeller
+ /// Mark Pollack (.NET)
+ public abstract class AbstractTransactionalDbProviderSpringContextTests : AbstractTransactionalSpringContextTests
+ {
+ ///
+ /// Holds the that this base class manages
+ ///
+ protected AdoTemplate adoTemplate;
+
+ ///
+ /// Did this test delete any tables? If so, we forbid transaction completion,
+ /// and only allow rollback.
+ ///
+ private bool zappedTables;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public AbstractTransactionalDbProviderSpringContextTests()
+ {
+ }
+
+ ///
+ /// Sets the DbProvider, via Dependency Injection.
+ ///
+ /// The IDbProvider.
+ public IDbProvider DbProvider
+ {
+ set { adoTemplate = new AdoTemplate(value); }
+ }
+
+ ///
+ /// Gets or sets the AdoTemplate that this base class manages.
+ ///
+ /// The ADO template.
+ public AdoTemplate AdoTemplate
+ {
+ get { return adoTemplate; }
+ }
+
+ ///
+ /// Convenient method to delete all rows from these tables.
+ /// Calling this method will make avoidance of rollback by calling
+ /// SetComplete() impossible.
+ ///
+ ///
+ protected void DeleteFromTables(String[] names)
+ {
+ for (int i = 0; i < names.Length; i++)
+ {
+ int rowCount = this.adoTemplate.ExecuteNonQuery(CommandType.Text, "DELETE FROM " + names[i]);
+ if (logger.IsInfoEnabled)
+ {
+ logger.Info("Deleted " + rowCount + " rows from table " + names[i]);
+ }
+ }
+ this.zappedTables = true;
+ }
+
+ ///
+ /// Overridden to prevent the transaction committing if a number of tables have been
+ /// cleared, as a defensive measure against accidental permanent wiping of a database.
+ ///
+ protected override void SetComplete()
+ {
+ if (this.zappedTables)
+ {
+ throw new InvalidOperationException("Cannot set complete after deleting tables");
+ }
+ base.SetComplete();
+ }
+
+ ///
+ /// Counts the rows in given table.
+ ///
+ /// Name of the table to count rows in.
+ /// The number of rows in the table
+ protected int CountRowsInTable(String tableName)
+ {
+ return (int) adoTemplate.ExecuteScalar(CommandType.Text, "SELECT COUNT(0) FROM " + tableName);
+
+ }
+
+ //TODO ExecuteScript...
+
+ }
+}
\ No newline at end of file
diff --git a/src/Spring/Spring.Testing.Microsoft/Testing/Microsoft/AbstractTransactionalSpringContextTests.cs b/src/Spring/Spring.Testing.Microsoft/Testing/Microsoft/AbstractTransactionalSpringContextTests.cs
new file mode 100644
index 00000000..2ecbbd82
--- /dev/null
+++ b/src/Spring/Spring.Testing.Microsoft/Testing/Microsoft/AbstractTransactionalSpringContextTests.cs
@@ -0,0 +1,306 @@
+#region License
+
+/*
+ * Copyright 2002-2009 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#endregion
+
+
+using System;
+using Spring.Transaction;
+using Spring.Transaction.Support;
+
+namespace Spring.Testing.Microsoft
+{
+ ///
+ /// Convenient superclass for tests that should occur in a transaction, but normally
+ /// will roll the transaction back on the completion of each test.
+ ///
+ ///
+ ///
This is useful in a range of circumstances, allowing the following benefits:
+ ///
+ ///
Ability to delete or insert any data in the database, without affecting other tests
+ ///
Providing a transactional context for any code requiring a transaction
+ ///
Ability to write anything to the database without any need to clean up.
+ ///
+ ///
+ ///
This class is typically very fast, compared to traditional setup/teardown scripts.
+ ///
+ ///
If data should be left in the database, call the SetComplete()
+ /// method in each test. The "DefaultRollback" property, which defaults to "true",
+ /// determines whether transactions will complete by default.
+ ///
+ ///
It is even possible to end the transaction early; for example, to verify lazy
+ /// loading behavior of an O/R mapping tool. (This is a valuable away to avoid
+ /// unexpected errors when testing a web UI, for example.) Simply call the
+ /// endTransaction() method. Execution will then occur without a
+ /// transactional context.
+ ///
+ ///
The StartNewTransaction() method may be called after a call to
+ /// EndTransaction() if you wish to create a new transaction, quite
+ /// independent of the old transaction. The new transaction's default fate will be to
+ /// roll back, unless setComplete() is called again during the scope of the
+ /// new transaction. Any number of transactions may be created and ended in this way.
+ /// The final transaction will automatically be rolled back when the test case is
+ /// torn down.
+ ///
+ ///
Transactional behavior requires a single object in the context implementing the
+ /// IPlatformTransactionManager interface. This will be set by the superclass's
+ /// Dependency Injection mechanism. If using the superclass's Field Injection mechanism,
+ /// the implementation should be named "transactionManager". This mechanism allows the
+ /// use of this superclass even when there's more than one transaction manager in the context.
+ ///
+ ///
This superclass can also be used without transaction management, if no
+ /// IPlatformTransactionManager object is found in the context provided. Be careful about
+ /// using this mode, as it allows the potential to permanently modify data.
+ /// This mode is available only if dependency checking is turned off in
+ /// the AbstractDependencyInjectionSpringContextTests superclass. The non-transactional
+ /// capability is provided to enable use of the same subclass in different environments.
+ ///
+ ///
+ ///
+ /// Rod Johnson
+ /// Juergen Hoeller
+ /// Rick Evans
+ /// Mark Pollack (.NET)
+ public abstract class AbstractTransactionalSpringContextTests : AbstractDependencyInjectionSpringContextTests
+ {
+ ///
+ /// The transaction manager to use
+ ///
+ protected IPlatformTransactionManager transactionManager;
+
+ ///
+ /// Should we roll back by default?
+ ///
+ private bool defaultRollback = true;
+
+ ///
+ /// Should we commit the current transaction?
+ ///
+ private bool complete = false;
+
+ ///
+ /// Number of transactions started
+ ///
+ private int transactionsStarted = 0;
+
+ ///
+ /// Default transaction definition is used.
+ /// Subclasses can change this to cause different behaviour.
+ ///
+ private ITransactionDefinition transactionDefinition = new DefaultTransactionDefinition();
+
+ ///
+ /// TransactionStatus for this test. Typical subclasses won't need to use it.
+ ///
+ protected ITransactionStatus transactionStatus;
+
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public AbstractTransactionalSpringContextTests()
+ {
+ }
+
+ ///
+ /// Sets the transaction manager to use.
+ ///
+ public IPlatformTransactionManager TransactionManager
+ {
+ set { transactionManager = value; }
+ }
+
+ ///
+ /// Sets the default rollback flag.
+ ///
+ public bool DefaultRollback
+ {
+ set { defaultRollback = value; }
+ }
+
+ ///
+ /// Set the to be used
+ ///
+ ///
+ /// Defaults to
+ ///
+ protected ITransactionDefinition TransactionDefinition
+ {
+ set { transactionDefinition = value; }
+ }
+
+ ///
+ /// Prevents the transaction.
+ ///
+ protected virtual void PreventTransaction()
+ {
+ this.transactionDefinition = null;
+ }
+
+
+ ///
+ /// Creates a transaction
+ ///
+ protected override void OnTestInitialize()
+ {
+ this.complete = !this.defaultRollback;
+
+ if (this.transactionManager == null)
+ {
+ logger.Info("No transaction manager set: test will NOT run within a transaction");
+ }
+ else if (this.transactionDefinition == null)
+ {
+ logger.Info("No transaction definition set: test will NOT run within a transaction");
+ }
+ else
+ {
+ OnSetUpBeforeTransaction();
+ StartNewTransaction();
+ try
+ {
+ OnSetUpInTransaction();
+ }
+ catch (Exception)
+ {
+ EndTransaction();
+ throw;
+ }
+ }
+ }
+
+
+ ///
+ /// Callback method called before transaction is setup.
+ ///
+ protected virtual void OnSetUpBeforeTransaction()
+ {
+ }
+
+ ///
+ /// Callback method called after transaction is setup.
+ ///
+ protected virtual void OnSetUpInTransaction()
+ {
+ }
+
+ ///
+ /// rollback the transaction.
+ ///
+ protected override void OnTestCleanup()
+ {
+ // Call onTearDownInTransaction and end transaction if the transaction is still active.
+ if (this.transactionStatus != null && !this.transactionStatus.Completed)
+ {
+ try
+ {
+ OnTearDownInTransaction();
+ }
+ finally
+ {
+ EndTransaction();
+ }
+ }
+ // Call onTearDownAfterTransaction if there was at least one transaction,
+ // even if it has been completed early through an endTransaction() call.
+ if (this.transactionsStarted > 0)
+ {
+ OnTearDownAfterTransaction();
+ }
+ }
+
+ ///
+ /// Callback before rolling back the transaction.
+ ///
+ protected virtual void OnTearDownInTransaction()
+ {
+ }
+
+ ///
+ /// Callback after rolling back the transaction.
+ ///
+ protected virtual void OnTearDownAfterTransaction()
+ {
+ }
+
+ ///
+ /// Set the complete flag..
+ ///
+ protected virtual void SetComplete()
+ {
+ if (this.transactionManager == null)
+ {
+ throw new InvalidOperationException("No transaction manager set");
+ }
+ this.complete = true;
+ }
+
+ ///
+ /// Ends the transaction.
+ ///
+ protected virtual void EndTransaction()
+ {
+ if (this.transactionStatus != null)
+ {
+ try
+ {
+ if (!this.complete)
+ {
+ this.transactionManager.Rollback(this.transactionStatus);
+ logger.Info("Rolled back transaction after test execution");
+ }
+ else
+ {
+ this.transactionManager.Commit(this.transactionStatus);
+ logger.Info("Committed transaction after test execution");
+ }
+ }
+ finally
+ {
+ this.transactionStatus = null;
+ }
+ }
+ }
+
+ ///
+ /// Starts the new transaction.
+ ///
+ protected void StartNewTransaction()
+ {
+ if (this.transactionStatus != null)
+ {
+ throw new InvalidOperationException("Cannot start new transaction without ending existing transaction: " +
+ "Invoke endTransaction() before startNewTransaction()");
+ }
+ if (this.transactionManager == null)
+ {
+ throw new InvalidOperationException("No transaction manager set");
+ }
+
+ this.transactionStatus = this.transactionManager.GetTransaction(this.transactionDefinition);
+ ++this.transactionsStarted;
+ this.complete = !this.defaultRollback;
+
+ if (logger.IsInfoEnabled)
+ {
+ logger.Info("Began transaction (" + this.transactionsStarted + "): transaction manager [" +
+ this.transactionManager + "]; default rollback = " + this.defaultRollback);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Spring/Spring.Testing.NUnit/AssemblyInfo.cs b/src/Spring/Spring.Testing.NUnit/AssemblyInfo.cs
index 074c740a..03bb47d6 100644
--- a/src/Spring/Spring.Testing.NUnit/AssemblyInfo.cs
+++ b/src/Spring/Spring.Testing.NUnit/AssemblyInfo.cs
@@ -1,5 +1,5 @@
using System;
using System.Reflection;
-[assembly: AssemblyTitle("Spring.Net NUnit support")]
+[assembly: AssemblyTitle("Spring.Testing.NUnit")]
[assembly: AssemblyDescription("Interfaces and classes that provide NUnit integration in Spring.Net")]
\ No newline at end of file
diff --git a/test/Spring/Spring.Testing.Microsoft.Tests/AssemblyInfo.cs b/test/Spring/Spring.Testing.Microsoft.Tests/AssemblyInfo.cs
new file mode 100644
index 00000000..c388fe56
--- /dev/null
+++ b/test/Spring/Spring.Testing.Microsoft.Tests/AssemblyInfo.cs
@@ -0,0 +1,10 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+//
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+//
+[assembly: AssemblyTitle("Spring.Testing.Microsoft Tests")]
+[assembly: AssemblyDescription("Unit tests for Spring.Testing.Microsoft assembly")]
\ No newline at end of file
diff --git a/test/Spring/Spring.Testing.Microsoft.Tests/Spring.Testing.Microsoft.Tests.2008.csproj b/test/Spring/Spring.Testing.Microsoft.Tests/Spring.Testing.Microsoft.Tests.2008.csproj
new file mode 100644
index 00000000..1a9769d3
--- /dev/null
+++ b/test/Spring/Spring.Testing.Microsoft.Tests/Spring.Testing.Microsoft.Tests.2008.csproj
@@ -0,0 +1,87 @@
+
+
+ Debug
+ AnyCPU
+ 9.0.30729
+ 2.0
+ {7321149A-47C6-4FBA-9D1A-26FD6815381B}
+ Library
+ Properties
+ Spring
+ Spring.Testing.Microsoft.Tests
+ v2.0
+ 512
+ {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+
+
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+ False
+ ..\..\..\lib\Net\2.0\Common.Logging.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {710961A3-0DF4-49E4-A26E-F5B9C044AC84}
+ Spring.Core.2008
+
+
+ {AE00E5AB-C39A-436F-86D2-33BFE33E2E40}
+ Spring.Data.2008
+
+
+ {2E10A8D3-B8FF-4699-90B8-E621659C58DD}
+ Spring.Testing.Microsoft.2008
+
+
+ {44B16BAA-6DF8-447C-9D7F-3AD3D854D904}
+ Spring.Core.Tests.2008
+
+
+ {ACD39D47-1811-40FA-9E7E-5DEA5B9CE6C0}
+ Spring.Data.Tests.2008
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/Spring/Spring.Testing.Microsoft.Tests/Spring.Testing.Microsoft.Tests.dll.config b/test/Spring/Spring.Testing.Microsoft.Tests/Spring.Testing.Microsoft.Tests.dll.config
new file mode 100644
index 00000000..0cfa9c7b
--- /dev/null
+++ b/test/Spring/Spring.Testing.Microsoft.Tests/Spring.Testing.Microsoft.Tests.dll.config
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/Spring/Spring.Testing.Microsoft.Tests/Testing/Microsoft/AbstractDependencyInjectionSpringContextTestsTests.cs b/test/Spring/Spring.Testing.Microsoft.Tests/Testing/Microsoft/AbstractDependencyInjectionSpringContextTestsTests.cs
new file mode 100644
index 00000000..9257c54e
--- /dev/null
+++ b/test/Spring/Spring.Testing.Microsoft.Tests/Testing/Microsoft/AbstractDependencyInjectionSpringContextTestsTests.cs
@@ -0,0 +1,130 @@
+#region License
+
+/*
+ * Copyright 2002-2009 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#endregion
+
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Spring.Context;
+using Spring.Context.Support;
+
+namespace Spring.Testing.Microsoft
+{
+ ///
+ /// Summary description for AbstractDependencyInjectionSpringContextTestsTests.
+ ///
+ [TestClass]
+ public class AbstractDependencyInjectionSpringContextTestsTests
+ {
+ private class TestAbstractDependencyInjectionSpringContextTests :AbstractDependencyInjectionSpringContextTests
+ {
+ public static readonly string[] CONFIGLOCATIONS = new string[] {"assembly://Spring.Testing.Microsoft.Tests/Spring.Testing.Microsoft/TestApplicationContext.xml"};
+
+ public TestAbstractDependencyInjectionSpringContextTests()
+ {}
+
+ public TestAbstractDependencyInjectionSpringContextTests(bool registerWithContextRegistry)
+ {
+ base.RegisterContextWithContextRegistry = registerWithContextRegistry;
+ }
+
+ public IConfigurableApplicationContext ApplicationContext
+ {
+ get { return base.applicationContext; }
+ }
+
+ protected override string[] ConfigLocations
+ {
+ get { return CONFIGLOCATIONS; }
+ }
+
+ public new bool HasCachedContext(object key)
+ {
+ return base.HasCachedContext(key);
+ }
+ }
+
+ private TestAbstractDependencyInjectionSpringContextTests fixtureInstance ;
+
+ [TestCleanup]
+ public void TearDown()
+ {
+ AbstractSpringContextTests.ClearContextCache();
+ }
+
+ [TestMethod]
+ public void RegistersWithContextRegistryByDefault()
+ {
+ fixtureInstance = new TestAbstractDependencyInjectionSpringContextTests();
+ Assert.IsTrue(fixtureInstance.RegisterContextWithContextRegistry);
+ }
+
+ [TestMethod]
+ public void UnregistersFromContextRegistryWhenDirty()
+ {
+ fixtureInstance = new TestAbstractDependencyInjectionSpringContextTests();
+ Assert.IsTrue(fixtureInstance.RegisterContextWithContextRegistry);
+ fixtureInstance.TestInitialize();
+ Assert.IsTrue( ContextRegistry.IsContextRegistered(fixtureInstance.ApplicationContext.Name) );
+ fixtureInstance.TestCleanup();
+ Assert.IsTrue(ContextRegistry.IsContextRegistered(fixtureInstance.ApplicationContext.Name));
+ fixtureInstance.TestInitialize();
+ Assert.IsTrue(ContextRegistry.IsContextRegistered(fixtureInstance.ApplicationContext.Name));
+ fixtureInstance.SetDirty();
+ fixtureInstance.TestCleanup();
+ Assert.IsFalse(ContextRegistry.IsContextRegistered(fixtureInstance.ApplicationContext.Name));
+ }
+
+ [TestMethod]
+ public void DoesNotRegisterContextWithContextRegistry()
+ {
+ fixtureInstance = new TestAbstractDependencyInjectionSpringContextTests();
+ Assert.IsTrue(fixtureInstance.RegisterContextWithContextRegistry);
+ fixtureInstance.RegisterContextWithContextRegistry = false;
+ fixtureInstance.TestInitialize();
+ Assert.IsFalse( ContextRegistry.IsContextRegistered(fixtureInstance.ApplicationContext.Name) );
+ fixtureInstance.TestCleanup();
+ Assert.IsFalse( ContextRegistry.IsContextRegistered(fixtureInstance.ApplicationContext.Name) );
+ }
+
+ [TestMethod]
+ public void CachesApplicationContexts()
+ {
+ fixtureInstance = new TestAbstractDependencyInjectionSpringContextTests(false);
+ fixtureInstance.TestInitialize();
+ Assert.IsNotNull(fixtureInstance.ApplicationContext);
+ Assert.AreEqual(1, fixtureInstance.LoadCount); // context has been loaded
+ Assert.IsTrue(fixtureInstance.HasCachedContext(TestAbstractDependencyInjectionSpringContextTests.CONFIGLOCATIONS));
+ fixtureInstance.TestCleanup();
+
+ TestAbstractDependencyInjectionSpringContextTests otherFixtureInstance = new TestAbstractDependencyInjectionSpringContextTests(false);
+ otherFixtureInstance.TestInitialize();
+ Assert.IsNotNull(otherFixtureInstance.ApplicationContext);
+ Assert.AreEqual(0, otherFixtureInstance.LoadCount); // context was obtained from cache
+ Assert.AreSame(fixtureInstance.ApplicationContext, otherFixtureInstance.ApplicationContext);
+ otherFixtureInstance.SetDirty(); // purge cache and dispose cached instances
+ Assert.IsFalse(fixtureInstance.HasCachedContext(TestAbstractDependencyInjectionSpringContextTests.CONFIGLOCATIONS));
+ otherFixtureInstance.TestCleanup();
+ otherFixtureInstance = new TestAbstractDependencyInjectionSpringContextTests(false);
+ otherFixtureInstance.TestInitialize();
+ Assert.IsNotNull(otherFixtureInstance.ApplicationContext);
+ Assert.AreEqual(1, otherFixtureInstance.LoadCount); // context was reloaded because of SetDirty() above
+ Assert.AreNotSame(fixtureInstance.ApplicationContext, otherFixtureInstance.ApplicationContext);
+ otherFixtureInstance.TestCleanup();
+ }
+ }
+}
diff --git a/test/Spring/Spring.Testing.Microsoft.Tests/Testing/Microsoft/TestApplicationContext.xml b/test/Spring/Spring.Testing.Microsoft.Tests/Testing/Microsoft/TestApplicationContext.xml
new file mode 100644
index 00000000..a5702f11
--- /dev/null
+++ b/test/Spring/Spring.Testing.Microsoft.Tests/Testing/Microsoft/TestApplicationContext.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/Spring/Spring.Testing.Microsoft.Tests/app.config b/test/Spring/Spring.Testing.Microsoft.Tests/app.config
new file mode 100644
index 00000000..83ff1365
--- /dev/null
+++ b/test/Spring/Spring.Testing.Microsoft.Tests/app.config
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/Spring/Spring.Testing.NUnit.Tests/Testing/NUnit/AbstractDependencyInjectionSpringContextTestsTests.cs b/test/Spring/Spring.Testing.NUnit.Tests/Testing/NUnit/AbstractDependencyInjectionSpringContextTestsTests.cs
index 9a9199c3..89642ced 100644
--- a/test/Spring/Spring.Testing.NUnit.Tests/Testing/NUnit/AbstractDependencyInjectionSpringContextTestsTests.cs
+++ b/test/Spring/Spring.Testing.NUnit.Tests/Testing/NUnit/AbstractDependencyInjectionSpringContextTestsTests.cs
@@ -1,4 +1,23 @@
-using System;
+#region License
+
+/*
+ * Copyright 2002-2009 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#endregion
+
using NUnit.Framework;
using Spring.Context;
using Spring.Context.Support;