Index: DEPENDENCIES.md
===================================================================
diff -u -r1bb6c7bb53b378ce4f48f21a35caba0aab4a7e4b -r09baf8dc969f6901a51bda3d65b8a206ba2f3b8b
--- DEPENDENCIES.md (.../DEPENDENCIES.md) (revision 1bb6c7bb53b378ce4f48f21a35caba0aab4a7e4b)
+++ DEPENDENCIES.md (.../DEPENDENCIES.md) (revision 09baf8dc969f6901a51bda3d65b8a206ba2f3b8b)
@@ -44,6 +44,7 @@
| OxyPlot.WindowsForms | 1.0.0 | MIT | https://github.com/oxyplot/oxyplot |
| Piping | 16.2.1.4574 | AGPL-3.0 | https://repos.deltares.nl/repos/FailureMechanisms/FailureMechanisms/DikesPiping |
| QuickGraph | 3.6.61119.7 | MS-PL | https://www.nuget.org/packages/QuickGraph |
+| NSubstitute | 4.4.0 | BSD-3-Clause | https://github.com/nsubstitute/NSubstitute |
| RhinoMocks | 3.6.1 | BSD-3-Clause | https://github.com/hibernating-rhinos/rhino-mocks |
| SmartThreadPool.dll | 2.2.4 | MS-PL | https://github.com/amibar/SmartThreadPool |
| Stub.System.Data.SQLite.Core.NetFramework | 1.0.117 | MS-PL | https://system.data.sqlite.org/index.html/doc/trunk/www/downloads.wiki |
Index: Riskeer/Common/test/Riskeer.Common.Data.TestUtil/AssessmentSectionTestHelper.cs
===================================================================
diff -u -r9339a780307cdb21ebe38cbd3aa8811e2c98d980 -r09baf8dc969f6901a51bda3d65b8a206ba2f3b8b
--- Riskeer/Common/test/Riskeer.Common.Data.TestUtil/AssessmentSectionTestHelper.cs (.../AssessmentSectionTestHelper.cs) (revision 9339a780307cdb21ebe38cbd3aa8811e2c98d980)
+++ Riskeer/Common/test/Riskeer.Common.Data.TestUtil/AssessmentSectionTestHelper.cs (.../AssessmentSectionTestHelper.cs) (revision 09baf8dc969f6901a51bda3d65b8a206ba2f3b8b)
@@ -25,6 +25,7 @@
using System.Linq;
using Core.Common.Base.Data;
using Core.Common.TestUtil;
+using NSubstitute;
using Rhino.Mocks;
using Riskeer.Common.Data.AssessmentSection;
using Riskeer.Common.Data.Contribution;
@@ -44,8 +45,21 @@
///
/// Creates a stub of with that is not linked.
///
- /// The mock repository to create the stub with.
/// A stubbed .
+ public static IAssessmentSection CreateAssessmentSectionStub()
+ {
+ var assessmentSection = Substitute.For();
+ assessmentSection.HydraulicBoundaryData.Returns(new HydraulicBoundaryData());
+ assessmentSection.ReferenceLine.Returns(new ReferenceLine());
+
+ return assessmentSection;
+ }
+
+ ///
+ /// Creates a stub of with that is not linked.
+ ///
+ /// The Rhino mock repository to create the stub with.
+ /// A stubbed .
public static IAssessmentSection CreateAssessmentSectionStub(MockRepository mockRepository)
{
var assessmentSection = mockRepository.Stub();
@@ -60,7 +74,6 @@
/// Creates a stub of .
///
/// The failure mechanism to set the contribution for.
- /// The mock repository to create the stub with.
/// The path to the hydraulic boundary database (optional).
/// Whether or not to use preprocessor closure (optional).
/// A stubbed .
@@ -71,6 +84,30 @@
///
///
public static IAssessmentSection CreateAssessmentSectionStub(IFailureMechanism failureMechanism,
+ string hrdFilePath = null,
+ bool usePreprocessorClosure = false)
+ {
+ IFailureMechanism[] failureMechanisms = GetFailureMechanisms(failureMechanism);
+
+ var assessmentSection = Substitute.For();
+ assessmentSection.Id.Returns("21");
+ assessmentSection.FailureMechanismContribution.Returns(new FailureMechanismContribution(0.1, 1.0 / 30000));
+ assessmentSection.GetFailureMechanisms().Returns(failureMechanisms);
+ assessmentSection.HydraulicBoundaryData.Returns(GetHydraulicBoundaryData(hrdFilePath, usePreprocessorClosure));
+ assessmentSection.ReferenceLine.Returns(new ReferenceLine());
+
+ return assessmentSection;
+ }
+
+ ///
+ /// Creates a stub of .
+ ///
+ /// The failure mechanism to set the contribution for.
+ /// The Rhino mock repository to create the stub with.
+ /// The path to the hydraulic boundary database (optional).
+ /// Whether or not to use preprocessor closure (optional).
+ /// A stubbed .
+ public static IAssessmentSection CreateAssessmentSectionStub(IFailureMechanism failureMechanism,
MockRepository mockRepository,
string hrdFilePath = null,
bool usePreprocessorClosure = false)
Index: Riskeer/Common/test/Riskeer.Common.Data.TestUtil/Riskeer.Common.Data.TestUtil.csproj
===================================================================
diff -u -re3d1ad7847ae5897d8764d49a2be8faa1490dc9e -r09baf8dc969f6901a51bda3d65b8a206ba2f3b8b
--- Riskeer/Common/test/Riskeer.Common.Data.TestUtil/Riskeer.Common.Data.TestUtil.csproj (.../Riskeer.Common.Data.TestUtil.csproj) (revision e3d1ad7847ae5897d8764d49a2be8faa1490dc9e)
+++ Riskeer/Common/test/Riskeer.Common.Data.TestUtil/Riskeer.Common.Data.TestUtil.csproj (.../Riskeer.Common.Data.TestUtil.csproj) (revision 09baf8dc969f6901a51bda3d65b8a206ba2f3b8b)
@@ -21,6 +21,12 @@
3.8.1
+
+ 4.4.0
+
+
+ 1.0.16
+
3.6.1
Index: Riskeer/Common/test/Riskeer.Common.IO.TestUtil/CustomCalculationConfigurationWriterDesignGuidelinesTestFixture.cs
===================================================================
diff -u -r9339a780307cdb21ebe38cbd3aa8811e2c98d980 -r09baf8dc969f6901a51bda3d65b8a206ba2f3b8b
--- Riskeer/Common/test/Riskeer.Common.IO.TestUtil/CustomCalculationConfigurationWriterDesignGuidelinesTestFixture.cs (.../CustomCalculationConfigurationWriterDesignGuidelinesTestFixture.cs) (revision 9339a780307cdb21ebe38cbd3aa8811e2c98d980)
+++ Riskeer/Common/test/Riskeer.Common.IO.TestUtil/CustomCalculationConfigurationWriterDesignGuidelinesTestFixture.cs (.../CustomCalculationConfigurationWriterDesignGuidelinesTestFixture.cs) (revision 09baf8dc969f6901a51bda3d65b8a206ba2f3b8b)
@@ -25,8 +25,8 @@
using System.Security.AccessControl;
using Core.Common.IO.Exceptions;
using Core.Common.TestUtil;
+using NSubstitute;
using NUnit.Framework;
-using Rhino.Mocks;
using Riskeer.Common.IO.Configurations;
using Riskeer.Common.IO.Configurations.Export;
@@ -41,9 +41,7 @@
public void Write_CalculationOfTypeOtherThanGiven_ThrowsCriticalFileWriteExceptionWithInnerArgumentException()
{
// Setup
- var mocks = new MockRepository();
- var calculation = mocks.Stub();
- mocks.ReplayAll();
+ var calculation = Substitute.For();
string filePath = TestHelper.GetScratchPadPath("test.xml");
@@ -67,8 +65,6 @@
{
File.Delete(filePath);
}
-
- mocks.VerifyAll();
}
[Test]
Index: Riskeer/Common/test/Riskeer.Common.IO.TestUtil/Riskeer.Common.IO.TestUtil.csproj
===================================================================
diff -u -r08e8d26a0715f0f3db57c1d3e86256aa06934db4 -r09baf8dc969f6901a51bda3d65b8a206ba2f3b8b
--- Riskeer/Common/test/Riskeer.Common.IO.TestUtil/Riskeer.Common.IO.TestUtil.csproj (.../Riskeer.Common.IO.TestUtil.csproj) (revision 08e8d26a0715f0f3db57c1d3e86256aa06934db4)
+++ Riskeer/Common/test/Riskeer.Common.IO.TestUtil/Riskeer.Common.IO.TestUtil.csproj (.../Riskeer.Common.IO.TestUtil.csproj) (revision 09baf8dc969f6901a51bda3d65b8a206ba2f3b8b)
@@ -21,8 +21,11 @@
3.8.1
-
- 3.6.1
+
+ 4.4.0
+
+ 1.0.16
+
\ No newline at end of file
Index: plan-replaceRhinoMocksWithNSubstitute.prompt.md
===================================================================
diff -u -r2b7b6c53b3a7b69bc318e36db92c8dd6131413a1 -r09baf8dc969f6901a51bda3d65b8a206ba2f3b8b
--- plan-replaceRhinoMocksWithNSubstitute.prompt.md (.../plan-replaceRhinoMocksWithNSubstitute.prompt.md) (revision 2b7b6c53b3a7b69bc318e36db92c8dd6131413a1)
+++ plan-replaceRhinoMocksWithNSubstitute.prompt.md (.../plan-replaceRhinoMocksWithNSubstitute.prompt.md) (revision 09baf8dc969f6901a51bda3d65b8a206ba2f3b8b)
@@ -1,15 +1,21 @@
## Plan: Replace Rhino.Mocks with NSubstitute
-Migrate test projects from Rhino.Mocks to NSubstitute in controlled phases: establish an API translation baseline, convert shared test utilities first, run pilot conversions in high-usage test suites, then scale by domain and finally remove Rhino package references. This reduces regression risk around strict/replay semantics while keeping CI green and making future test maintenance easier.
+Migrate test projects from Rhino.Mocks to NSubstitute in controlled phases using a dual-stack transition: shared test helpers expose both Rhino.Mocks and NSubstitute implementations until repository usage of Rhino is zero. This reduces regression risk around strict/replay semantics while keeping CI green and allowing incremental suite migration.
### Steps
1. [ ] Inventory Rhino usage and package references across `Riskeer/**/*.cs` and `Riskeer/**/*.csproj`, tagging `MockRepository`, `Expect`, `Stub`, `Arg`, `ReplayAll`, `VerifyAll`, `WhenCalled`, `IgnoreArguments`, `Repeat`.
2. [ ] Define and publish a migration rulebook in `DEPENDENCIES.md` with approved `NSubstitute` patterns and unsupported Rhino idioms.
-3. [ ] Convert shared helpers first (for example `Riskeer/Common/test/Riskeer.Common.Data.TestUtil/AssessmentSectionTestHelper.cs`) to stop propagating `MockRepository` usage.
+3. [ ] Convert shared helpers first (for example `Riskeer/Common/test/Riskeer.Common.Data.TestUtil/AssessmentSectionTestHelper.cs`) to dual-stack helpers: keep Rhino-based overloads and add/keep NSubstitute overloads.
4. [ ] Execute a pilot in two heavy suites (`Riskeer/WaveImpactAsphaltCover/test/Riskeer.WaveImpactAsphaltCover.Service.Test`, `Riskeer/Common/test/Riskeer.Common.IO.Test`), then refine rules from real failures.
5. [ ] Roll out by domain test folders (Service -> Plugin -> Integration -> Forms/Data), updating each `*.csproj` from `RhinoMocks` to `NSubstitute`.
-6. [ ] Remove remaining Rhino references and enforce a gate that blocks new `using Rhino.Mocks;` in `Riskeer.sln` scope.
+6. [ ] When Rhino usage reaches zero in tests, remove Rhino helper overloads and Rhino package references, then enforce a gate that blocks new `using Rhino.Mocks;` in `Riskeer.sln` scope.
+### Dual-Stack Policy (Temporary)
+1. Test helper projects may reference both `RhinoMocks` and `NSubstitute` during migration.
+2. Helper APIs must keep Rhino-compatible overloads for existing tests and NSubstitute-first overloads for new tests.
+3. No helper should remove Rhino overloads until repository-wide Rhino call sites are zero.
+4. Per migration batch, Rhino usage must be non-increasing.
+
### API Mapping
| Rhino.Mocks pattern | NSubstitute equivalent | Notes |
|---|---|---|
@@ -26,17 +32,17 @@
### Phased Rollout
1. **Phase 0 - Baseline:** create inventory and migration rulebook; freeze new Rhino usage.
-2. **Phase 1 - Foundations:** migrate shared `*TestUtil` helpers and common fixtures first.
-3. **Phase 2 - Pilot:** migrate selected high-usage suites, capture edge cases (strict expectations, callbacks, argument matching).
-4. **Phase 3 - Scale-out:** migrate remaining test projects by bounded domain batches with small PRs.
-5. **Phase 4 - Decommission:** remove `RhinoMocks` package references and add policy checks preventing reintroduction.
+2. **Phase 1 - Foundations (Dual-Stack):** migrate shared `*TestUtil` helpers and common fixtures to provide both Rhino and NSubstitute implementations.
+3. **Phase 2 - Pilot:** migrate selected high-usage suites to NSubstitute, capture edge cases (strict expectations, callbacks, argument matching), while helpers remain dual-stack.
+4. **Phase 3 - Scale-out:** migrate remaining test projects by bounded domain batches with small PRs; track Rhino burn-down per batch.
+5. **Phase 4 - Decommission:** after Rhino usage is zero, remove Rhino helper overloads and `RhinoMocks` package references, then add policy checks preventing reintroduction.
### Verification Gates
1. **Gate A (Baseline):** Rhino usage inventory approved; all migration rules mapped for discovered APIs.
-2. **Gate B (Per phase):** no `using Rhino.Mocks;` in migrated scope; project builds and its tests pass.
+2. **Gate B (Per phase):** Rhino usage in migrated scope is non-increasing; project builds and its tests pass.
3. **Gate C (Pilot exit):** translated callback/argument/count patterns validated in pilot suites.
-4. **Gate D (Rollout exit):** all targeted `*.csproj` use `NSubstitute`; no `RhinoMocks` `PackageReference` remains.
-5. **Gate E (Final):** repository-wide search finds zero Rhino APIs and CI remains green for full test matrix.
+4. **Gate D (Rollout exit):** all targeted migrated suites use `NSubstitute`; remaining Rhino usage is explicitly tracked and accepted only in not-yet-migrated suites/helpers.
+5. **Gate E (Final):** repository-wide search finds zero Rhino APIs and zero Rhino package references, then CI remains green for full test matrix.
### Further Considerations
1. Should strict-mock intent be preserved exactly (Option A) or simplified to intent-focused `Received()` assertions (Option B)?