- Overview
- Guides
- Concepts
- Considerations And Constraints
- Absolute File References
- Assembly Colocation Assumptions
- Concurrent Use Of Test Resources
- Cross Application Domain Testing
- Heavily Executed Code Under Test
- Implicit File Dependencies
- Multi Threaded Tests
- Netstandard Test Projects
- Project Atomicity
- Project Build Platform And Configuration
- Rdi Data Point Location
- Test Atomicity
- Unique Test Names
- Using NCrunch With Source Control
- Reference
- Global Configuration
- Overview
- Auto Adjust Clashing Marker Colours
- Build Log Verbosity
- Build Process Memory Limit
- Capabilities Of This Computer
- Coverage Marker Style
- Cpu Cores Assigned To NCrunch Or Ide
- Custom Environment Variables
- Disable Global Hotkey
- Engine Hosting Strategy
- Fast Lane Threads
- Fast Lane Threshold
- Grid Maximum Reconnection Attempts
- Grid Reconnection Delay
- Impact Detection Mode
- Listening Port
- Log To Output Window
- Logging Verbosity
- Marker Colours
- Max Failing Test Trace Log Size
- Max Number Of Processing Threads
- Max Passing Test Trace Log Size
- Max Test Runners To Pool
- NCrunch Tool Window Colors
- Node Id (Name)
- Password
- Performance Aggregation Type
- Performance Display Sensitivity
- Pipeline Optimisation Priority
- Rdi Storage Settings
- Sliding Build Delay
- Snapshot Storage Directory
- Solution Storage Data Limit
- Spinner Colours
- Terminate Test Runners On Complete
- Test Process Memory Limit
- Tests To Execute On This Machine
- Text Output Font
- Workspace Base Path
- Solution Configuration
- Overview
- Additional Files For Grid Processing
- Additional Files To Include
- Allow Parallel Test Execution
- Allow Tests In Parallel With Themselves
- Infer Project References Using Assembly
- Instrumentation Mode
- NCrunch Cache Storage Path
- Only Consider Tests Outofdate If Impacted
- Project Config File Storage Path
- Show Coverage For Tests
- Show Metrics For Tests
- Tests To Execute Automatically
- Project Configuration
- Overview
- Additional Files To Include
- Allow Dynamic Code Contract Checks
- Allow Static Code Contract Checks
- Analyse Line Execution Times
- Autodetect Nuget Build Dependencies
- Build Priority
- Build Process Cpu Architecture
- Build Sdk
- Collect Control Flow During Execution
- Consider Inconclusive Tests As Passing
- Copied Project Dependencies
- Copy Referenced Assemblies To Workspace
- Custom Build Properties
- Data Storage File Size
- Default Test Timeout
- Detect Stack Overflow
- Enable Rdi
- Files Excluded From Auto Build
- Framework Utilisation Types
- Ignore This Component Completely
- Implicit Project Dependencies
- Include Static References In Workspace
- Instrument Output Assembly
- Method Data Limit
- Ms Test Thread Apartment State
- Preload Assembly References
- Prevent Signing Of Assembly
- Proxy Process File Path
- Rdi Cache Size
- Required Capabilities
- Restrict Tostring Usage
- Run Pre Or Post Build Events
- String Length Limit
- Track File Dependencies
- Use Build Configuration
- Use Build Platform
- Use Cpu Architecture
- Runtime Framework
- Overview
- Atomic Attribute
- Category Attribute
- Collect Control Flow Attribute
- Distribute By Capabilities
- Duplicate By Dimensions
- Enable Rdi Attribute
- Environment Class
- Exclusively Uses Attribute
- Inclusively Uses Attribute
- Isolated Attribute
- Method Data Limit Attribute
- Requires Capability Attribute
- Restrict Tostring Attribute
- Serial Attribute
- String Length Limit Attribute
- Timeout Attribute
- Uses Threads Attribute
- Global Configuration
- Troubleshooting
- Tools
- Keyboard Shortcuts
- Manual Installation Instructions
Tests That Build Their Own Application Domains
Cross-process and cross-appdomain tests require special attention when working with NCrunch.
Because these tests build their own environments inside NCrunch workspaces, they are often coded with certain assumptions about the structure of their environment and the location of the assemblies within it.
If your tests make assumptions about having their referenced assemblies inside their working directory, you may experience problems with these assemblies not being present in their expected places when NCrunch runs these tests. A simple solution is to enable the copy referenced assemblies to workspace setting for all the projects involved, but this will massively decrease build performance. A better solution is to look at other ways of resolving the locations of assemblies required in the domain.
The NCrunchEnvironment.GetAllAssemblyLocations() method is a useful way to retrieve a list of the file locations of every assembly that can be potentially loaded into the test runtime application domain. This method loads its data from an environment variable that will always be present in every application domain or process launched from the NCrunch test environment. A unfortunate drawback is that the method is only available when working with NCrunch - it will not be available under other test runners. This means that code making use of it needs to be conditional on NCrunch execution.
The following example contains code that creates a custom application domain during test execution. This code has been updated to use the NCrunchEnvironment.GetAllAssemblyLocations() method to find assemblies needed inside its application domain.
Note that this code will fail with a stack overflow if the version of NCrunch.Framework you are referencing is not installed in the GAC of the machine executing the test. NCrunch installs this assembly into the GAC automatically when the NCrunch installer is run, but you should beware of referencing uninstalled versions of this assembly through Nuget.
using System; using System.IO; using System.Reflection; using System.Security; using System.Security.Permissions; using System.Security.Policy; using Microsoft.VisualStudio.TestTools.UnitTesting; using ReferencedProject; namespace MyTestProject { [TestClass] public class Fixture { [TestMethod] public void TestThatCreatesAnApplicationDomainIncludingAReferencedAssembly() { var setup = new AppDomainSetup { ApplicationName = "Application", ApplicationBase = Directory.GetCurrentDirectory(), }; var evidence = new Evidence(); evidence.AddHostEvidence(new Zone(SecurityZone.MyComputer)); var appDomain = AppDomain.CreateDomain( "MyDomain", evidence, setup, new PermissionSet(PermissionState.Unrestricted) ); var classInAppDomain = (ClassInApplicationDomain)appDomain.CreateInstanceFromAndUnwrap( typeof(ClassInApplicationDomain).Assembly.Location, typeof(ClassInApplicationDomain).FullName ); classInAppDomain.RunCodeInApplicationDomain(); } } public class ClassInApplicationDomain : MarshalByRefObject { public void RunCodeInApplicationDomain() { #if NCRUNCH // This code isn't needed for other test runners or NCrunch with the // 'Copy Referenced Assemblies To Workspace' setting enabled, because they // will have the ReferencedProject.dll sitting in the current directory. AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve; #endif runCodeInReferencedAssembly(); } private void runCodeInReferencedAssembly() { // When no effort is made to find required assemblies via the AssemblyResolve method, // NCrunch will blow up here, as it won't be able to find ReferencedProject.dll. var c = new ClassInReferencedProject(); c.DoStuff(); } private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) { // Search through the known assembly locations returned from the NCrunchEnvironment.GetAllAssemblyLocations method, // and load any assembly with a name matching the one we're looking for var shortAssemblyName = getShortAssemblyName(args.Name); foreach (var knownAssemblyLocation in NCrunch.Framework.NCrunchEnvironment.GetAllAssemblyLocations()) if (string.Compare(Path.GetFileNameWithoutExtension(knownAssemblyLocation), shortAssemblyName, true) == 0) return Assembly.LoadFrom(knownAssemblyLocation); return null; } private static string getShortAssemblyName(string assemblyName) { // The CLR can attempt to resolve assemblies using long names - so we truncate the name to make matching easier. if (assemblyName.Contains(",")) return assemblyName.Substring(0, assemblyName.IndexOf(',')); return assemblyName; } } }