| Revit Version | NuGet Package | Status |
|---|---|---|
| 2025 | ✓ Supported | |
| 2026 | ✓ Supported |
RevitXunit.TestAdapter is a powerful xUnit test adapter that enables seamless integration testing of Autodesk Revit add-ins directly within the Revit environment. Write standard xUnit tests that automatically load Revit models, access the full Revit API, and execute inside a running Revit instance while reporting results back to Visual Studio Test Explorer or your CI/CD pipeline. Perfect for BIM developers who need reliable, automated testing of Revit functionality without the complexity of manual testing workflows.
- Projects
- Key Features
- Getting Started
- Quick Example
- What Can You Do?
- Full Attribute Reference
- Local Path Support and Special Folders
- Test Output Logs
- Example: Worksharing Test
- Advanced
- Requirements
- How It Works
- Example tests
- RevitAddin.Xunit – Add-in loaded into Revit. Implements xUnit runner and a named pipe server.
- RevitAdapterCommon – Shared helper library for connecting the adapters to the Revit pipe.
- RevitXunitAdapter – Test adapter for xUnit. Discovers tests and sends execution commands to the Revit process.
- RevitTestFramework.Xunit – xUnit-specific framework components and runners.
- RevitTestFramework.Xunit.Contracts – Attributes and helpers shared by the add-in and test projects.
- RevitDebuggerHelper – .NET Framework 4.8 helper for Visual Studio debugger operations with advanced multi-instance support.
- MyRevitTestsXunit – Example xUnit test library that uses the
RevitFactattribute.
- 🔧 Standard xUnit Tests - Write familiar xUnit tests with
[RevitFact]attribute - 📁 Automatic Model Loading - Load local files, cloud models, or use active documents
- 🔌 Full Revit API Access - Tests run inside Revit with complete API access
- 🔍 Visual Studio Integration - Results appear in Test Explorer with intelligent debugger support
- 🚀 CI/CD Ready - Works with dotnet test and build pipelines
- 📝 Version Placeholders - Dynamic Revit version path resolution
- 🎯 Multiple Parameter Types - Inject Document, UIApplication, or both
- 🐛 Advanced Debugging - Smart Visual Studio instance detection for seamless debugging experience
- 🏗️ Worksharing Support - Advanced workset and central model management with detailed logging
To use the test framework, add the following NuGet package reference to your test project:
<PackageReference Include="RevitXunit.TestAdapter" Version="$(RevitVersion).*" />
Or use this example test project file:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
<RevitVersion>2025</RevitVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="RevitXunit.TestAdapter" Version="$(RevitVersion).*" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Nice3point.Revit.Api.RevitAPI" Version="$(RevitVersion).*" />
<PackageReference Include="Nice3point.Revit.Api.RevitAPIUI" Version="$(RevitVersion).*" />
</ItemGroup>
</Project>using Xunit;
using RevitTestFramework.Xunit;
using Autodesk.Revit.DB;
public class MyRevitTests
{
[RevitFact(@"C:\Models\sample.rvt")]
public void Should_CountWalls(Document doc)
{
var walls = new FilteredElementCollector(doc)
.WhereElementIsNotElementType()
.OfClass(typeof(Wall))
.ToElements();
Assert.True(walls.Count > 0);
}
}- Use
[RevitFact]to run tests inside Revit. - Inject
Document,UIApplication, or both as parameters.
- Active Document:
[RevitFact] public void TestActiveDoc(Document? doc) { }
- Local File:
[RevitFact(@"C:\Models\sample.rvt")] public void TestLocalFile(Document doc) { }
- Cloud Model:
[RevitFact("project-guid", "model-guid")] public void TestCloudModel(Document doc) { }
- Version Placeholder:
[RevitFact(@"C:\Program Files\Autodesk\Revit {RevitVersion}\Samples\sample.rvt")] public void TestWithVersionPlaceholder(Document doc) { }
- DetachOption:
DoNotDetach(default)DetachAndPreserveWorksetsDetachAndDiscardWorksetsClearTransmittedSaveAsNewCentral
- WorksetsToOpen:
- Open specific worksets by ID:
[RevitFact(@".\Project1.rvt", WorksetsToOpen = [1,2,5])]
- Open specific worksets by ID:
- CloseModel:
- Close the model after test:
[RevitFact(CloseModel = true)]
- Close the model after test:
Document docorDocument? docUIApplication uiapp- Both:
TestMethod(UIApplication uiapp, Document doc) CancellationToken cancellationToken
- Specify region:
[RevitFact(CloudRegion.EMEA, projectGuid: "...", modelGuid: "...")]
- Automatic debugger attach/detach to correct Visual Studio instance
- Environment variables:
REVIT_DEBUG_DISABLE_AUTO_DETACH=trueREVIT_DEBUG_SYNC_DETACH=true
- Log level set via
%LOCALAPPDATA%\RevitTestRunner\Logs\loglevel.txt - Levels:
Trace,Debug,Info,Warn,Error,Fatal
| Attribute/Parameter | Description |
|---|---|
localPath |
Path to local Revit file |
projectGuid, modelGuid |
Cloud model GUIDs |
CloudRegion |
Cloud region (e.g., EMEA, US) |
WorksetsToOpen |
Array of workset IDs to open |
DetachOption |
How to detach from central (see above) |
CloseModel |
Close model after test |
You can specify the Revit file path in [RevitFact] using:
- Absolute paths (e.g.
C:\Models\sample.rvt) - Relative paths (e.g.
@".\Project1.rvt")- Relative paths are resolved from the test output directory (where your test assembly DLL is built)
- Special folders:
%PROGRAMFILES%(e.g.%PROGRAMFILES%\Autodesk\Revit {RevitVersion}\Samples\sample.rvt)%USERPROFILE%(e.g.%USERPROFILE%\Documents\Revit\MyModel.rvt)
- Version placeholders:
{RevitVersion}is replaced with the actual Revit version at runtime
Examples:
[RevitFact(localPath: @"%PROGRAMFILES%\Autodesk\Revit {RevitVersion}\Samples\Snowdon Towers Sample Architectural.rvt")]
public void TestSampleModel(Document doc) { }
[RevitFact(localPath: @".\Project1.rvt")]
public void TestRelativePath(Document doc) { }The test output logs provide detailed information about the test run and Revit environment. Key information includes:
- Test Discovery and Execution: Which tests were found, which models or cloud GUIDs are used, and which tests are being executed.
- Add-in and Revit Instance Management: Whether the Revit add-in was installed, which Revit process is used, and how the connection is established.
- Model Loading: The path, title, and type of the model being opened, DetachOption, WorksetsToOpen, and whether the model is workshared.
- Workset Information: IDs, names, open/closed status, and ownership of all worksets in the model. This is especially useful for configuring
WorksetsToOpenin your tests. - Test Results: Pass/fail status, execution time, and any errors or exceptions.
- Cleanup: Whether models or Revit processes are closed after the test run.
You can use the log output to debug test setup, extract workset IDs, and verify the test environment and results.
[RevitFact(@".\Project1.rvt", WorksetsToOpen = [0], DetachOption = DetachOption.DetachAndPreserveWorksets, CloseModel = true)]
public void DetachAndPreserveWorksets_ShouldDetachModelAndPreserveWorksets(Document document)
{
Assert.NotNull(document);
Assert.Equal("Project1_detached", document.Title);
var userWorksets = new FilteredWorksetCollector(document)
.OfKind(WorksetKind.UserWorkset)
.ToWorksets();
Assert.NotEmpty(userWorksets);
var openWorksets = userWorksets.Where(w => w.IsOpen).ToList();
Assert.Single(openWorksets);
}When working with workshared models, you may need to specify workset IDs to open. You can extract the available workset IDs from the test output logs. Look for log lines like these in the test output:
Revit.RevitTestModelHelper [INFO] 08:46:24.405: --- Workset Information ---
Revit.RevitTestModelHelper [INFO] 08:46:24.413: Central Model Path: Autodesk.Revit.DB.ModelPath
Revit.RevitTestModelHelper [INFO] 08:46:24.427: Total Worksets: 2
Revit.RevitTestModelHelper [INFO] 08:46:24.431: Workset Details:
Revit.RevitTestModelHelper [INFO] 08:46:24.441: ID: 0, Name: 'Workset1', Status: CLOSED, READ-ONLY, Owner: No Owner
Revit.RevitTestModelHelper [INFO] 08:46:24.447: ID: 183, Name: 'Shared Views, Levels, Grids', Status: CLOSED, READ-ONLY, Owner: No Owner
Use these IDs in your test attribute:
[RevitFact(@".\Project1.rvt", WorksetsToOpen = [0, 183], DetachOption = DetachOption.DetachAndPreserveWorksets, CloseModel = true)]
public void OpenSpecificWorksets(Document document)
{
// ...test code...
}- Debugger: Smart attach/detach, multi-VS support
- Logging: Detailed workset/model logs, configurable level
- CI/CD: Works with
dotnet testand build pipelines
- Autodesk Revit 2025+
- .NET 8.0
- Visual Studio or
dotnet test - .NET Framework 4.8 (for debugger helper)
- Discovery: Finds
[RevitFact]tests - Communication: Connects to Revit via named pipes
- Model Loading: Opens models with worksharing config
- Debugger Setup: Attaches debugger if needed
- Execution: Runs tests in Revit
- Reporting: Results to Test Explorer/CI
- Cleanup: Detach debugger, clean resources
See the following files in the MyRevitTestsXunit project for real-world test examples:
- RollbackTests.cs
- OpenLocalModelTests.cs
- ApplicationTests.cs
- CancellationTokenTests.cs
- CloudModelTests.cs
For details on how to manage and configure CI/CD for this repository, see CI/CD Pipeline Guide.