I am working on a unit test for a project and I cannot figure out how to get NSubstitute to work the way I would expect it to. The issue I am having is that the code I was to substitute is in a while loop and depending on what is returned from the substituted value determines if the loop continues.
What I would like to do is have Process() return a different result based on what is passed in. I have tried
api.Process(Arg.Is<IEnumerable<int>>(new[] {1,2,3}, Arg.Any<bool>()).Returns(new ProcessingResult(){Success = true, IdsNotProcessed = List<int>{30}});
but it does not seems to work as processingResult comes back null because NSubstitue is not matching the argument.
[Test]
public void TestTwoLoops()
{
var api = Substitute.For<IApi>();
api.Process(/*list containing 1,2,3*/, Arg.Any<bool>()).Returns(new ProcessingResult(){Success = true, IdsNotProcessed = List<int>{30}});
api.Process(/*list containing 30*/, Arg.Any<bool>()).Returns(new List<int>{});
var sut = new WidgetMaker(api);
sut.MakeWidget();
}
public class WidgetMaker
{
public WidgetMaker(IApi api)
{
_api = api;
}
public void MakeWidgets(IEnumerable<int> widgetIds)
{
var idsToProcess = widgetIds.ToList();
while(true)
{
if(!idsToProcess.Any())
{
berak;
}
var processingResult = _api.Process(idsToProcess, false);
if(processingResult.Success)
{
idsToProcess.Clear();
idsToProcess.AddRange(processingResult.IdsNotProcessed);
}
else
{
break;
}
}
}
private IApi _api;
}
As I was writing this question, the answer came to me, but I have a feeling others might find this helpful.
Using the overload that accepts a predicate and using the SequenceEqualExtension method with a parameter of new[] {/values I want to be input/}
api.Process(Arg.Is<IEnumerable<int>>(x => x.SequenceEqual(new[] {1,2,3}, Arg.Any<bool>())).Returns(new ProcessingResult(){Success = true, IdsNotProcessed = List<int>{30}});
Related
I am trying to Test a function which I have below to get all active categories which will use a relation predicate bucket. The mocked data in the initializer class adds three objects which are both active and not deleted. It adds a fourth to the end which is deleted and not active.
During the test, the call will return all four objects, and not the expected number of three. This is where I am stuck with.
I have tried making _randomCategories as a Queryable object, but this also failed.
There is a lot of code in the first class so it may be hard to follow, so each part is broken into regions saying which part it performs, i.e. Test Setup, Mock Data, & the Tests themselves.
The Mock Data region are the expected results. May not be necessary for my needs here as it is not used in this other than to get the expected count, but it may be relevant to the overall structure of the tests.
CategoryServiceTests.cs
#region Test Setup
public class CategoryServiceFixture : IDisposable
{
public CategoryService Sut { get; private set; }
private SystemRepository SystemRepository { get; set; }
private Mock<CategoryRepository> _categoryRepositoryMock;
private List<CategoryEntity> _randomCategories;
public CategoryServiceFixture()
{
// Init Category List
_randomCategories = CategoryEntityInitializer.GetAllMockCategories();
// Init repository
_categoryRepositoryMock = new Mock<CategoryRepository>(new object[] { null });
// Setup mocking behavior
// BaseRepository
_categoryRepositoryMock
.Setup(m => m.GetAll(It.IsAny<IRelationPredicateBucket>(), It.IsAny<IDataAccessAdapter>()))
.Returns(_randomCategories);
SystemRepository = new SystemRepository(category: _categoryRepositoryMock.Object);
Sut = new CategoryService(this.SystemRepository);
}
public void Dispose()
{
//Sut.Dispose();
}
}
[CollectionDefinition("CategoryService Collection")]
public class CategoryServiceCollection : ICollectionFixture<CategoryServiceFixture> { }
#endregion
#region Mock Data
public static class CategoryRepositoryMockData
{
public static IEnumerable<object> GetCategories
{
get
{
yield return new object[] { 1, new List<CategoryEntity>() {
new CategoryEntity
{
CategoryId = 1,
Name = "Test1",
IsDeleted = false,
IsActive = true
},
new CategoryEntity
{
CategoryId = 2,
Name = "Test2",
IsDeleted = false,
IsActive = true
},
new CategoryEntity
{
CategoryId = 3,
Name = "Test3",
IsDeleted = false,
IsActive = true
}
}};
}
}
}
#endregion
#region Tests
[Collection("CategoryService Collection")]
public class CategoryServiceTests
{
private CategoryServiceFixture _fixture;
public CategoryServiceTests(CategoryServiceFixture fixture)
{
_fixture = fixture;
}
[Theory]
[Trait("Category", "Get All Active Categories")]
[Trait("Expected", "Return Correct")]
[MemberData("GetCategories", MemberType = typeof(CategoryRepositoryMockData))]
public void GetActiveCategories_ShouldReturn(int id, IList<CategoryEntity> expectedCategoryObjects)
{
var result = _fixture.Sut.GetActiveCategories();
Assert.Equal(expectedCategoryObjects.Count, result.Count);
}
}
#endregion
This class generates the mock database objects. This is what is supposed to be searched through and select the correct ones from the list.
CategoryEntityInitializer.cs
public static class CategoryEntityInitializer
{
public static List<CategoryEntity> GetAllMockCategories()
{
List<CategoryEntity> _categories = new List<CategoryEntity>();
for (var i = 1; i <= 3; i++)
{
var entity = new CategoryEntity()
{
CategoryId = i,
Name = String.Format("{0}{1}", "Test", i),
IsDeleted = false,
IsActive = true
};
_categories.Add(entity);
}
var lastEntity = new CategoryEntity()
{
CategoryId = 4,
Name = String.Format("{0}{1}", "Test", 4),
IsDeleted = true,
IsActive = false
};
_categories.Add(lastEntity);
return _categories;
}
}
This class is where the predicate is.
CategoryService.cs
public class CategoryService : BaseService
{
public IList<CategoryModel> GetActiveCategories()
{
var bucket = new RelationPredicateBucket();
bucket.PredicateExpression.Add(CategoryFields.IsDeleted == false);
bucket.PredicateExpression.Add(CategoryFields.IsActive == true);
var categoriesEntities = _systemRepository.Category.GetAll(bucket);
return CategoryMapper.MapToModels(categoriesEntities);
}
}
The rest of the code structure works fine for every other test and across different test classes. This is the first time I have had to test the relation predicate bucket.
UPDATE 18/05/16
I found the solution to the problem. Answer in the below code.
_categoryRepositoryMock
.Setup(m => m.GetAll(It.IsAny<IRelationPredicateBucket>(), It.IsAny<IDataAccessAdapter>()))
.Returns(new Func<IRelationPredicateBucket, IDataAccessAdapter, IEnumerable<CategoryEntity>>(
(bucket, adapter) => _randomCategories.Where(a => a.IsDeleted == false && a.IsActive == true)));
Old Answer 11/05/16
I believe I have found part of the answer. In mocking the repository, I was returning all four objects, no matter if the predicate bucket would work or not.
_categoryRepositoryMock
.Setup(m => m.GetAll(It.IsAny<IRelationPredicateBucket>(), It.IsAny<IDataAccessAdapter>()))
.Returns(_randomCategories);
This will cause it to return all four as I have not implemented the bucket to filter out the matches. I thought that the .Returns would place the data into the repository as if returned from the database and then get filtered with the bucket.
What I have found out is that the call to the repository does not go to the one it would if it was running normally, but instead goes to the mocked repository and this is where you need to filter the data to be returned.
It needs to be done something similar to this.
_categoryRepositoryMock
.Setup(m => m.GetAll(It.IsAny<IRelationPredicateBucket>(), It.IsAny<IDataAccessAdapter>()))
.Returns(
(IRelationPredicateBucket bucket) => _randomCategories.Where(x => x.Name.Equals(bucket)));
Although this still give me a problem as I don't know how to get inside the bucket to match to the list, it is at least heading in the correct direction.
NOTE: I have also found from searching that another reason for this type of failure is due to the code, in this case the function being called is too complex to be tested. It should be seperated into smaller chucks to make it less complex and to test each part seperately.
Before
public class CategoryService : BaseService
{
public IList<CategoryModel> GetActiveCategories()
{
var bucket = new RelationPredicateBucket();
bucket.PredicateExpression.Add(CategoryFields.IsDeleted == false);
bucket.PredicateExpression.Add(CategoryFields.IsActive == true);
var categoriesEntities = _systemRepository.Category.GetAll(bucket);
return CategoryMapper.MapToModels(categoriesEntities);
}
}
After
public class CategoryService : BaseService
{
public IList<CategoryModel> GetActiveCategories()
{
var bucket = GetActiveCategoriesBucket();
var categoriesEntities = _systemRepository.Category.GetAll(bucket);
return CategoryMapper.MapToModels(categoriesEntities);
}
public RelationPredicateBucket GetActiveCategoriesBucket()
{
var bucket = new RelationPredicateBucket();
bucket.PredicateExpression.Add(CategoryFields.IsDeleted == false);
bucket.PredicateExpression.Add(CategoryFields.IsActive == true);
return bucket;
}
}
I have the code below which I would like to test, but I'm not sure whether it is possible or not.
I have EF repositories and they are put together to a class as public properties. I don't know exactly whether it is bad solution or not, but it is easier to manage the code and its dependencies. Only the testability is still a question.
Purpose of my test is injecting data via
administrationRepository.ModuleScreen.GetAll()
method and catch the result. I know that it can be tested once it is deployed, but I want the tests in build time in order to have as fast feedback as possible.
I went through questions and answers here, but I cannot find answers. In my code I got to the point where the property is set up, but when I call the administrationRepoMock.Object.ModuleScreen.GetAll() ReSharper offers only the methods coming from Entitiy Framework and not the Moq related functions.
It is possible what I want? If so, how? Is my design suitable for this? If not can you give me articles, urls where I can see examples?
Repository:
public interface IModuleScreen
{
IEnumerable<DomainModel.Administration.ModuleScreen> GetAll();
}
public interface IAdministrationRepository
{
IModuleScreen ModuleScreen { get; }
}
public partial class AdministrationRepository : IAdministrationRepository
{
public virtual IModuleScreen ModuleScreen { get; private set; }
public AdministrationRepository( IModuleScreen moduleScreen )
{
this.ModuleScreen = moduleScreen;
}
}
Application:
public partial class DigitalLibraryApplication : IDigitalLibraryApplication
{
private IAdministrationRepository _administrationRepository;
private IMapper.IMapper.IMapper _mapper;
private IDiLibApplicationHelper _dilibApplicationHelper;
#region Ctor
public DigitalLibraryApplication( IAdministrationRepository administrationRepository, IMapper.IMapper.IMapper mapper, IDiLibApplicationHelper diLibApplicationHelper)
{
_administrationRepository = administrationRepository;
_mapper = mapper;
_dilibApplicationHelper = diLibApplicationHelper;
}
#endregion
public IEnumerable<ModuleScreenContract> GetModuleScreens()
{
//inject data here
IEnumerable<ModuleScreen> result = _administrationRepository.ModuleScreen.GetAll();
List<ModuleScreenContract> mappedResult = _mapper.MapModuleScreenToModuleScreenContracts(result);
return mappedResult;
}
}
Test code:
[Test]
public void ItCalls_ModuleRepository_Get_Method()
{
List<SayusiAndo.DiLib.DomainModel.Administration.ModuleScreen> queryResult = new List<SayusiAndo.DiLib.DomainModel.Administration.ModuleScreen>()
{
new DomainModel.Administration.ModuleScreen()
{
Id = 100,
},
};
var moduleScreenMock = new Mock<IModuleScreen>();
moduleScreenMock.Setup(c => c.GetAll()).Returns(queryResult);
administrationRepoMock.SetupProperty(c => c.ModuleScreen, moduleScreenMock.Object);
var mapperMock = new Mock<IMapper.IMapper.IMapper>();
var dilibApplicationHerlperMock = new Mock<IDiLibApplicationHelper>();
IDigitalLibraryApplication app = new DigitalLibraryApplication( administrationRepoMock.Object, mapperMock.Object, dilibApplicationHerlperMock.Object );
app.GetModules();
//issue is here
administrationRepoMock.Object.ModuleScreen.GetAll() //???
}
Here is a refactoring of your test that passes when run. You can update the pass criteria to suit you definition of a successful test.
[Test]
public void ItCalls_ModuleRepository_Get_Method() {
// Arrange
List<ModuleScreen> queryResult = new List<ModuleScreen>()
{
new ModuleScreen()
{
Id = 100,
},
};
//Building mapped result from query to compare results later
List<ModuleScreenContract> expectedMappedResult = queryResult
.Select(m => new ModuleScreenContract { Id = m.Id })
.ToList();
var moduleScreenMock = new Mock<IModuleScreen>();
moduleScreenMock
.Setup(c => c.GetAll())
.Returns(queryResult)
.Verifiable();
var administrationRepoMock = new Mock<IAdministrationRepository>();
administrationRepoMock
.Setup(c => c.ModuleScreen)
.Returns(moduleScreenMock.Object)
.Verifiable();
var mapperMock = new Mock<IMapper>();
mapperMock.Setup(c => c.MapModuleScreenToModuleScreenContracts(queryResult))
.Returns(expectedMappedResult)
.Verifiable();
//NOTE: Not seeing this guy doing anything. What's its purpose
var dilibApplicationHerlperMock = new Mock<IDiLibApplicationHelper>();
IDigitalLibraryApplication app = new DigitalLibraryApplication(administrationRepoMock.Object, mapperMock.Object, dilibApplicationHerlperMock.Object);
//Act (Call the method under test)
var actualMappedResult = app.GetModuleScreens();
//Assert
//Verify that configured methods were actually called. If not, test will fail.
moduleScreenMock.Verify();
mapperMock.Verify();
administrationRepoMock.Verify();
//there should actually be a result.
Assert.IsNotNull(actualMappedResult);
//with items
CollectionAssert.AllItemsAreNotNull(actualMappedResult.ToList());
//There lengths should be equal
Assert.AreEqual(queryResult.Count, actualMappedResult.Count());
//And there should be a mapped object with the same id (Assumption)
var expected = queryResult.First().Id;
var actual = actualMappedResult.First().Id;
Assert.AreEqual(expected, actual);
}
Currently we are trying to implement some unittesting on our services. In the below service an order is created and a audit registration is made about the creation of an order. When writing the two tests (because we think the tests should be seperated to get tests with 1 responsibility) this was where I started with:
public class TestPacklineOrderManagementService
{
[Fact]
public void CreateNewProductWhenNoPacklineOrderIsAvailable()
{
IPackLineOrderRepository packLineOrderRepository = Substitute.For<IPackLineOrderRepository>();
packLineOrderRepository.GetActive(Arg.Any<PackLine>()).Returns(x => null);
var rawProductRepository = Substitute.For<IRawProductRepository>();
rawProductRepository.Get(1).Returns(new RawProduct {Id = 1});
var packlineRepository = Substitute.For<IPackLineRepository>();
packlineRepository.Get(1).Returns(new PackLine {Id = 1});
var auditRegistrationService = Substitute.For<IAuditRegistrationService>();
var packlineOrderManagementService = new PacklineOrderManagementService(packLineOrderRepository, rawProductRepository, packlineRepository, auditRegistrationService);
packlineOrderManagementService.SetProduct(1,1);
packLineOrderRepository.Received()
.Insert(Arg.Is<PackLineOrder>(x => x.PackLine.Id == 1 && x.Product.Id == 1));
}
[Fact]
public void AuditCreateNewProductWhenNoPacklineOrderIsAvailable()
{
IPackLineOrderRepository packLineOrderRepository = Substitute.For<IPackLineOrderRepository>();
packLineOrderRepository.GetActive(Arg.Any<PackLine>()).Returns(x=>null);
var rawProductRepository = Substitute.For<IRawProductRepository>();
rawProductRepository.Get(1).Returns(new RawProduct { Id = 1 });
var packlineRepository = Substitute.For<IPackLineRepository>();
packlineRepository.Get(1).Returns(new PackLine { Id = 1 });
var auditRegistrationService = Substitute.For<IAuditRegistrationService>();
var packlineOrderManagementService = new PacklineOrderManagementService(packLineOrderRepository, rawProductRepository, packlineRepository, auditRegistrationService);
packlineOrderManagementService.SetProduct(1, 1);
auditRegistrationService.Received()
.Audit(Arg.Is<PackLineOrderAudit>(item => item.Action == PackLineOrderAction.CreatePacklineOrder));
}
}
As you can see a lot of duplicate code. To prevent this I tried to refactor this and it resulted in the code below:
public class TestPacklineOrderManagementService2
{
[Fact]
public void CreateNewProductWhenNoPacklineOrderIsAvailable()
{
IPackLineOrderRepository packLineOrderRepository;
IAuditRegistrationService auditRegistrationService;
var packlineOrderManagementService = BuilderForCreateNewProductWhenNoPacklineOrderIsAvailable(out packLineOrderRepository, out auditRegistrationService);
packlineOrderManagementService.SetProduct(1,1);
packLineOrderRepository.Received().Insert(Arg.Any<PackLineOrder>());
}
[Fact]
public void AuditCreateNewProductWhenNoPacklineOrderIsAvailable()
{
IPackLineOrderRepository packLineOrderRepository;
IAuditRegistrationService auditRegistrationService;
var packlineOrderManagementService = BuilderForCreateNewProductWhenNoPacklineOrderIsAvailable(out packLineOrderRepository, out auditRegistrationService);
packlineOrderManagementService.SetProduct(1, 1);
auditRegistrationService.Received()
.Audit(Arg.Is<PackLineOrderAudit>(item => item.Action == PackLineOrderAction.CreatePacklineOrder));
}
private PacklineOrderManagementService BuilderForCreateNewProductWhenNoPacklineOrderIsAvailable(out IPackLineOrderRepository packLineOrderRepository,
out IAuditRegistrationService auditRegistrationService)
{
packLineOrderRepository = CreatePackLineOrderRepository(x => null);
auditRegistrationService = CreateAuditRegistrationService();
var rawProductRepository = CreateRawProductRepository(x => new RawProduct { Id = 1 });
var packlineRepository = CreatePacklineRepository(x => new PackLine { Id = 1 });
var packlineOrderManagementService = new PacklineOrderManagementService(packLineOrderRepository,
rawProductRepository, packlineRepository, auditRegistrationService);
return packlineOrderManagementService;
}
private IPackLineOrderRepository CreatePackLineOrderRepository(Func<CallInfo, PackLineOrder> getActiveResult)
{
IPackLineOrderRepository packLineOrderRepository = Substitute.For<IPackLineOrderRepository>();
packLineOrderRepository.GetActive(Arg.Any<PackLine>()).Returns(getActiveResult);
return packLineOrderRepository;
}
private IRawProductRepository CreateRawProductRepository(Func<CallInfo, RawProduct> getResult)
{
IRawProductRepository rawProductRepository = Substitute.For<IRawProductRepository>();
rawProductRepository.Get(1).Returns(getResult);
return rawProductRepository;
}
private IPackLineRepository CreatePacklineRepository(Func<CallInfo, PackLine> getResult)
{
IPackLineRepository packLineRepository = Substitute.For<IPackLineRepository>();
packLineRepository.Get(1).Returns(getResult);
return packLineRepository;
}
private IAuditRegistrationService CreateAuditRegistrationService()
{
return Substitute.For<IAuditRegistrationService>();
}
}
Is there any way to get a better code base for our unittests?
Better is very subjective, it depends a lot on how you define it. Some people might argue that your first example was better since all of the setup code is together in your test. I do have some feedback based on your code above though...
When you're writing tests, don't use the same value for two parameters to your system under test (SUT) unless they really are the same, it hides transposition errors. So, in your test, you're setting up one of your substitutes like this:
rawProductRepository.Get(1).Returns(new RawProduct {Id = 1});
Then calling your SUT:
packlineOrderManagementService.SetProduct(1,1);
Are the 1s in the SUT call related to the Repository setup? It's not at all clear which 1 is which...
This somewhat subjective, but if your test setup is exactly the same, do you really need to duplicate the test, with different asserts? Does it really make sense for the Audit to take place if the Insert hasn't etc?
If you do have groups of tests that have similar setups, then you could push the common bits into your classes constructor. You could also organise your tests using nested classes, something like this:
public class TestPacklineOrderManagementService
{
public class TestSetProduct {
IPackLineOrderRepository _packLineOrderRepository;
IRawProductRepository _rawProductRepository;
// etc
public TestSetProduct() {
_packLineOrderRepository = Substitute.For<IPackLineOrderRepository>();
_packLineOrderRepository.GetActive(Arg.Any<PackLine>()).Returns(x => null);
_rawProductRepository = Substitute.For<IRawProductRepository>();
// etc
}
[Fact]
public void CreateNewProductWhenNoPacklineOrderIsAvailable()
{
// Any test specific setup...
_packlineOrderManagementService.SetProduct(1,1);
_packLineOrderRepository.Received()
.Insert(Arg.Is<PackLineOrder>(x => x.PackLine.Id == 1
&& x.Product.Id == 1));
}
[Fact]
public void AuditCreateNewProductWhenNoPacklineOrderIsAvailable()
{
_packlineOrderManagementService.SetProduct(1, 1);
_auditRegistrationService.Received()
.Audit(Arg.Is<PackLineOrderAudit>(item =>
item.Action == PackLineOrderAction.CreatePacklineOrder));
}
}
public class TestSomeOtherScenario {
// tests...
}
}
This approach and make your tests more succinct and easier to follow, if they only contain the test specific information, but is it better? It's very subjective, some people (including the xunit team) don't like shared per test setups. Really it's about finding the approach that works for you and your team...
In Fluent Assertions when comparing objects with DateTime properties there are sometimes a slight mismatch in the milliseconds and the comparison fail. The way we get around it is to set the comparison option like so:
actual.ShouldBeEquivalentTo(expected,
options =>
options.Using<DateTime>(ctx => ctx.Subject.Should().BeCloseTo(ctx.Expectation))
.WhenTypeIs<DateTime>());
Is there a way to set this up once and have it always apply instead of having to specify it every time we call ShouldBeEquivalentTo?
Update1:
Tried the following approach but it doesn't seem to work, test fails on 1 millisecond difference. The new default does not seem to get called by the factory.
using System;
using FluentAssertions;
using FluentAssertions.Equivalency;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace UnitTestProject1
{
class Test
{
public DateTime TestDateTime { get; set; }
}
[TestClass]
public class UnitTest1
{
[TestMethod]
public void SettingFluentAssertionDefault()
{
// arrange
var defaultAssertionOptions = EquivalencyAssertionOptions<DateTime>.Default;
EquivalencyAssertionOptions<DateTime>.Default = () =>
{
var config = defaultAssertionOptions();
config.Using<DateTime>(ctx => ctx.Subject.Should().BeCloseTo(ctx.Expectation)).WhenTypeIs<DateTime>();
return config;
};
var testDateTime = DateTime.Now;
var expected = new Test {TestDateTime = testDateTime};
// act
var actual = new Test {TestDateTime = testDateTime.AddMilliseconds(1)};
// assert
actual.ShouldBeEquivalentTo(expected);
}
}
}
Now this can be done with the AssertionOptions static class. To use a simple example:
[TestInitialize]
public void TestInit() {
AssertionOptions.AssertEquivalencyUsing(options => options.ExcludingMissingMembers());
}
Or as in the example above:
AssertionOptions.AssertEquivalencyUsing(options =>
options.Using<DateTime>(ctx => ctx.Subject.Should().BeCloseTo(ctx.Expectation)).WhenTypeIs<DateTime>()
);
Actually, you can. The default configuration factory is exposed by the static property EquivalencyAssertionOptions<Test>.Default. You can easily assign an alternative configuration for a particular data type, or extend the default configuration with additional behavior. Something like:
var defaultAssertionOptions = EquivalencyAssertionOptions<Test>.Default;
EquivalencyAssertionOptions<Test>.Default = () =>
{
var config = defaultAssertionOptions();
config.Using<DateTime>(ctx => ctx.Subject.Should().BeCloseTo(ctx.Expectation)).WhenTypeIs<DateTime>();
return config;
};
If you want you can get the current default and tuck that away in some variable that you use from your factory method.
I am afraid the closest thing you can come to, is providing new methods
public static void ShouldBeEquivalentToDef<T>(this T subject, object expectation, string reason = "",
params object[] reasonArgs)
{
ShouldBeEquivalentToDef(subject, expectation, config => config, reason, reasonArgs);
}
public static void ShouldBeEquivalentToDef<T>(this T subject, object expectation,
Func<EquivalencyAssertionOptions<T>, EquivalencyAssertionOptions<T>> config, string reason = "", params object[] reasonArgs)
{
var context = new EquivalencyValidationContext
{
Subject = subject,
Expectation = expectation,
CompileTimeType = typeof (T),
Reason = reason,
ReasonArgs = reasonArgs
};
var defConstructedOptions = config(EquivalencyAssertionOptions<T>.Default());
defConstructedOptions.Using<DateTime>(ctx => ctx.Subject.Should().BeCloseTo(ctx.Expectation))
.WhenTypeIs<DateTime>()
new EquivalencyValidator(defConstructedOptions).AssertEquality(context);
}
I am trying to experiment with RhinoMocks, where I have to say I am a newbie and probably I don't get some obvious thing here. What I'm doing is something like :
[TestMethod]
public void SaveResponsibleUserFromChangeset()
{
var action = mocks.StrictMock<GenomeAction>();
var changeset = new ActionChangeset();
changeset.ResponsibleUser = new ChangeableProperty<UserIdentity>("Administrator") {IsChanged = true};
changeset.MarkAll(true);
using(mocks.Record())
{
Expect.Call(action.ResponsibleUser).SetPropertyAndIgnoreArgument();
}
using(mocks.Playback())
{
var persistor = new ActionPersistor(new MockIdentityResolver());
persistor.SaveActionChanges(changeset, action);
}
action.VerifyAllExpectations();
}
private class MockIdentityResolver : IIdentityResolver
{
public GenomeUser GetUser(UserIdentity identity)
{
var user = mocks.DynamicMock<GenomeUser>();
user.Username = identity.Username;
return user;
}
}
The intention is to have a very simple test which checks whether the SaveActionChanges method sets the ResponsibleUser property. As a part of this, it needs to resolve the user identity using the resolver, for which I have provided a mock implementation. Unfortunately, it seems I can't just return back another mock within the Playback mode, because it says (on the closing bracket of the second using) that The action is invalid when the object (of type GenomeUser) is in record state.
Any ideas of what is causing the trouble and how to overcome it ?
I think you need to create you new MockIdentityResolver() outside the mocks.Playback().
[TestMethod]
public void SaveResponsibleUserFromChangeset()
{
var action = mocks.StrictMock<GenomeAction>();
var changeset = new ActionChangeset();
var identityResolver;
changeset.ResponsibleUser = new ChangeableProperty<UserIdentity>("Administrator") {IsChanged = true};
changeset.MarkAll(true);
using(mocks.Record())
{
Expect.Call(action.ResponsibleUser).SetPropertyAndIgnoreArgument();
identityResolver = new MockIdentityResolver()
}
using(mocks.Playback())
{
var persistor = new ActionPersistor(identityResolver);
persistor.SaveActionChanges(changeset, action);
}
action.VerifyAllExpectations();
}
private class MockIdentityResolver : IIdentityResolver
{
public GenomeUser GetUser(UserIdentity identity)
{
var user = mocks.DynamicMock<GenomeUser>();
user.Username = identity.Username;
return user;
}
}
you should look at using the AAA syntax, it seems to be generally accepted that it's a clearer way of using stuff.