I am new to NHibernate and even newer to MOQ (or other similar frameworks). After searching online day and night (google + stackoverflow + others), I am turning here for help.
The scenario is (should be) simple. I am trying to unit test a call on a C# WCF service that uses NHibernate as the ORM layer. The method, after doing some initial work, finds a database to connect to, and then calls on the SessionProvider (a manager of session factories) to return a nhibernate session for a sharded DB. I am then trying to use ISession.Get<>() to retrieve an object from the database aand then do some work. The problem is that the GUID (the key for the entry that I am looking up in the db) is generated at the begining of the call and I have no way of knowing what it might be beforehand outside the scope of the WCF call. Hence, I cannot use sqllite or other techniques to pre-populate the necessary data to control the test. What I was hoping for was that I can somehow mock (inject a fake layer to?) the call to Session.Get to return an invalid object which should cause the WCF call to throw.
Here's the test code snippet:
var testRequest = ... (request DTO)
var dummyBadObject = ... (entity in DB)
var mock = new Mock<ISession>(MockBehavior.Strict);
mock.Setup(m => m.Get<SampleObject>(It.IsAny<Guid>())).Returns(dummyBadObject);
var exception = Assert.Throws<FaultException>(() => applicationService.SomeMethod(testRequest));
Assert.AreEqual(exception.Code.ToString(), SystemErrorFault.Code.ToString());
When I run this test, instead of interacting with the mock ISession object, the app service code calls the Get on the actual ISession object from the session factory, connects to the database and gets the right object. Seems like I am missing something very basic about mocks or injection. Any help will be appreciated.
Thanks,
Shawn
Based on our comments, the problem is that mocks are completely different from how you thought of them.
They don't magically intercept creations of classes derived from an interface. They are just dynamic implementations of it.
Creating a Mock<ISession> is not much different from creating a class that implements ISession. You still have to inject it in the services that depend on it.
You'll probably have to review your whole stack, as the capability to do this depends on a good decoupled design.
Suggested read: Inversion of control
I re-designed the components in my application to have a ServiceContext object which in turns holds all the other (what used to be static) components that the application uses. In this case, this would be the session provider (or the ISessionFactory cache), and similarly a WCF channel factory cache. The difference is that the ServiceContext provides methods to override the default instances of the different components allowing me to replace them with mock ones for testing and restoring the original ones when testing is done. This has allowed me to create a test where I mock all the way from the session cache to the ISession.Get/Save/Load etc.
var mockDatabaseSessionFactory = new Mock<DatabaseSessionManager>(MockBehavior.Strict);
var mockSession = new Mock<ISession>(MockBehavior.Strict);
var mockTransaction = new Mock<ITransaction>(MockBehavior.Strict);
mockDatabaseSessionFactory.Setup(x => x.GetIndividualMapDbSession()).Returns(mockSession.Object);
mockDatabaseSessionFactory.Setup(x => x.GetIndividualDbSession(It.IsAny<UInt32>())).Returns(mockSession.Object);
mockDatabaseSessionFactory.Setup(x => x.Dispose());
mockSession.Setup(x => x.BeginTransaction()).Returns(mockTransaction.Object);
mockSession.Setup(x => x.Dispose());
mockTransaction.Setup(x => x.Commit());
mockTransaction.Setup(x => x.Dispose());
// Setups to allow for the map insertion/deletion to pass
mockSession.Setup(x => x.Get<IndividualMap>(It.IsAny<string>())).Returns((IndividualMap)null);
mockSession.Setup(x => x.Load<IndividualMap>(It.IsAny<string>())).Returns((IndividualMap)null);
mockSession.Setup(x => x.Save(It.IsAny<IndividualMap>())).Returns(new object());
mockSession.Setup(x => x.Delete(It.IsAny<IndividualMap>()));
// Our test condition for this test: throw on attempt to save individual
mockSession.Setup(x => x.Save(It.IsAny<Individual>()))
.Throws(new FaultException(ForcedTestFault.Reason, ForcedTestFault.Code));
// Test it - but be sure to back up the previous database session factory
var originalDbSessionFactory = ServiceContext.DatabaseSessionManager;
ServiceContext.OverrideDatabaseSessionManager(mockDatabaseSessionFactory.Object);
try
{
var exception = Assert.Throws<FaultException>(() => applicationService.AddIndividual(addIndividualRequest));
Assert.IsTrue(ForcedTestFault.Code.Name.Equals(exception.Code.Name));
}
catch (Exception)
{
// Restore the original database session factory before rethrowing
ServiceContext.OverrideDatabaseSessionManager(originalDbSessionFactory);
throw;
}
ServiceContext.OverrideDatabaseSessionManager(originalDbSessionFactory);
ServiceContext.CommunicationManager.CloseChannel(applicationService);
Luckily the code design wasn't too bad o_O :) so i re-factored this bit easily and now code coverage is at 100! Thanks Diego for nudging me in the right direction.
Related
I am currently using Simple Injector for the first time. In my .NET project I am running test and mocking data returned from a web service and registering the object to the container like so
_container.Register<IWebServiceOrder>(() => mock.Object, Lifestyle.Transient);
This works fine. But in my tests I want to test the behavior of the system on a second call to the web service that will contain updated data, so the mock object will need to be updated.
By default Simple Injector does not allow Overriding existing registrations but the official website states it is possible to change this behavior like below.
https://simpleinjector.readthedocs.org/en/latest/howto.html#override-existing-registrations
container.Options.AllowOverridingRegistrations = true;
Unfortunately i still get an error when i try to register the object a second time even with the above code.
The container can't be changed after the first call to GetInstance, GetAllInstances and Verify
Any ideas on why this is happening?
Replacing an existing registration after you already worked with the container hardly ever has the behavior you would expect (and this holds for all DI libraries) and that's the reason why the Simple Injector container is locked. This is described in more details here (as #qujck already pointed out).
First of all, if you are writing unit tests, you shouldn't use a container at all. Your unit tests should create the class under test themselves, or you extract this logic to a convenient factory method, such as:
private static MailNotifier CreateMailNotifier(
IDeposit deposit = null, ISendMail mailSender = null, ILog logger = null)
{
return new MailNotifier(
deposit ?? Substitute.For<IDeposit>(),
mailSender ?? Substitute.For<ISendMail>(),
logger ?? Substitute.For<ILog>());
}
This factory method is a variation to the Test Data Builder pattern.
By making use of optional parameters, it allows the unit test to specify only the fake implementation it requires during testing:
public void Notify_WithValidUser_LogsAMessage()
{
// Arrange
var user = new User();
var logger = new FakeLogger();
MailNotifier sut = CreateMailNotifier(logger: logger);
// Act
sut.Notify(user);
// Assert
Assert.AreEqual(expected: 1, actual: logger.LoggedMessages.Count);
}
If you use a container, because creating the class under test by hand is too cumbersome, it indicates a problem in your class under test (most likely a Single Responsibility Principle violation). Prevent using tools to work around problems in your design; your code is speaking to you.
For integration tests however, it is much more usual to use the container, but in that case you should simply create a new container for each integration test. This way you can add or replace the IWebServiceOrder without any problem.
I have a repository and a consumer of that repository in some legacy code.
The consumer makes multiple method calls to the repository.
Each method call returns a huge resultset.
I do have an integration test that checks how the consumer and repository behave together, but it isn't good enough for me - it relies on a database connection, is painfully slow, and doesn't help me know whether the test fails because of changes to the repository, database, or consumer.
I'd like to convert this integration test to test the consumer in isolation - independent of the implementation of the repository.
But because it is legacy code the behaviour of which I do not fully understand yet and because the resultsets are huge, I can't stub out the repository by hand. If it were possible to write this by hand it would look like
var mockRepository = new Mock<IRepository>();
mockRepository.SetUp(r => r.GetCustomersInMarket(marketId: 3))
.Returns(
new List<Customer> {
new Customer {
...
},
new Customer {
...
},
... x 100 // large dataset
});
mockRepository.SetUp(r => r.GetProductsInMarket(marketId: 3))
.Returns(
...
);
... x 15 // many different calls need to be set up
var testee = new Consumer(mockRepository.Object); // using dependency injection
var report = testee.GenerateReport();
AssertReportMatchesExpectations(report); // some assertions
So what I'd prefer to do is (once)
var recordingProxy = new RecordingProxy<IRepository>(new Repository());
var testee = new Consumer(recordingProxy);
var report = testee.GenerateReport();
var methodCallLog = recordingProxy.GetLog();
and thereafter
var methodCallLog = GetStoredMethodCallLog(); // load persisted log from file or similar
var replayingProxy = new ReplayingProxy<IRepository>(methodCallLog);
var testee = new Consumer(replayingProxy);
var report = testee.GenerateReport();
AssertReportMatchesExpectations(report); // some assertions
I have started working on a generic tool to act as a proxy and record and replay traffic that goes across interface boundaries to solve this problem in general.
Is there already anything like this out there?
Are there other ways to solve the problem of stubbing repositories
to return large datasets
when the content of the dataset can only be understood by observing existing behaviour (because the author's intent is not clear).
If not, I'll be posting my tool as an answer to this question.
I've recently started using AutoFixture+AutoMoq and I'm trying to create an instance of Func<IDbConnection> (i.e., a connection factory).
var fixture = new Fixture().Customize(new AutoMoqCustomization());
var connectionFactory = fixture.Create<Func<IDbConnection>>();
This seems to work rather well:
My system under test can call the delegate and it will get a mock of IDbConnection
On which I can then call CreateCommand, which will get me a mock of IDbCommand
On which I can then call ExecuteReader, which will get me a mock of IDataReader
I now want to perform additional setups on the mock of IDataReader, such as make it return true when Read() is called.
From what I've read, I should be using Freeze for this:
var dataReaderMock = fixture.Freeze<Mock<IDataReader>>();
dataReaderMock.Setup(dr => dr.Read())
.Returns(true);
This doesn't seem to meet my expectations though. When I call IDbCommand.ExecuteReader, I'll get a different reader than the one I just froze/setup.
Here's an example:
var fixture = new Fixture().Customize(new AutoMoqCustomization());
var dataReaderMock = fixture.Freeze<Mock<IDataReader>>();
dataReaderMock.Setup(dr => dr.Read())
.Returns(true);
//true - Create<IDataReader> retrieves the data reader I just mocked
Assert.AreSame(dataReaderMock.Object, fixture.Create<IDataReader>());
//false - IDbCommand returns a different instance of IDataReader
Assert.AreSame(dataReaderMock.Object, fixture.Create<IDbCommand>().ExecuteReader());
What am I doing wrong? How do I get other fixtures, such as IDbCommand, to use the mocked instance of IDataReader?
As of 3.20.0, you can use AutoConfiguredMoqCustomization. This will automatically configure all mocks so that their members' return values are generated by AutoFixture.
E.g., IDbConnetion.CreateCommand will be automatically configured to return an IDbCommand from the fixture, and IDbCommand.ExecuteReader will be automatically configured to return an IDataReader from the fixture.
All of these tests should pass now:
var fixture = new Fixture().Customize(new AutoConfiguredMoqCustomization());
var dataReaderMock = fixture.Freeze<Mock<IDataReader>>();
dataReaderMock.Setup(dr => dr.Read())
.Returns(true);
//all pass
Assert.Same(dataReaderMock.Object, fixture.Create<IDataReader>());
Assert.Same(dataReaderMock.Object, fixture.Create<IDbCommand>().ExecuteReader());
Assert.Same(dataReaderMock.Object, fixture.Create<IDbConnection>().CreateCommand().ExecuteReader());
Assert.Same(dataReaderMock.Object, fixture.Create<Func<IDbConnection>>()().CreateCommand().ExecuteReader());
You have to Freeze the Mock<IDbCommand> as well – and setup the mock object (as a Stub) to return the existing dataReaderMock.Object instance.
If you add the following to the Arrange phase of you test, the test will pass:
var dbCommandStub =
fixture
.Freeze<Mock<IDbCommand>>()
.Setup(x => x.ExecuteReader())
.Returns(dataReaderMock.Object);
While the solution from Nikos works I would not I do not recommend mocking ado.net.
In my opinion your tests will probably be hard to understand, maintain and will not give you the confidence your tests should give you.
I would consider testing your data layer by going all the way to the database even though it is slower.
I would recommend reading this article regarding best practices for mocking:
http://codebetter.com/jeremymiller/2006/01/10/best-and-worst-practices-for-mock-objects/
Don't mock others:
http://aspiringcraftsman.com/2012/04/01/tdd-best-practices-dont-mock-others/
I don't know your exact situation but anyways I wanted to share this.
My implementation of unit of work and repository might be the root of the issue here.. but given that everywhere I look for a unit of work implementation I see a different one, I'm sure Ninject has a way of working around it.
So I'm injecting implementations of IRepository<T> into the constructor of my "unit of work".
_kernel.Bind<IRepository<SomeType1>>().To<RepoOfSomeType1>().WhenInjectedInto<IMyUoWFactory>();
_kernel.Bind<IRepository<SomeType2>>().To<RepoOfSomeType2>().WhenInjectedInto<IMyUoWFactory>();
...
I've set up the kernel to instantiate a DataContext in singleton scope which I thought would mean I'm injecting the same instance of this DataContext whenever I need it:
_kernel.Bind<DataContext>().ToConstructor(arg => new MyDataContext(arg.Inject<string>()))
.InSingletonScope() // pass same instance to all repositories?
("connection", _someConnectionString);
The problem I'm finding, is that each repository seems to have its own instance, plus the unit of work has its own as well - hence the exception I'm getting when I try to commit a transaction (something about cross-context transaction).
To top it all off, in certain specific situations I need the connection string to be dynamic, so that the unit of work can work off a database that's selected by the user - hence the "need" for a factory.
The result is that I have 1 connection per repository plus 1 connection per unit of work, which defeats the purpose of UoW (i.e. transactional data operations), and all this overhead, I think, is causing serious performance issues (running +/- 200,000 small data operations in... 3-4 hours!!).
This is how I'm creating the unit of work instance; I want to be able to inject repository implementations in there, yet still be able to use the connection string that the user asked for:
public MyUoWFactory(IRepository<Type1> type1repo, IRepository<Type2> type2repo,
IRepository<Type3> type3repo, IRepository<Type4> type4repo,
IRepository<Type5> type5repo, IRepository<Type6> type6repo)
{
_type1Repository = type1repo;
_type2Repository = type2repo;
_type3Repository = type3repo;
_type4Repository = type4repo;
_type5Repository = type5repo;
_type6Repository = type6repo;
}
public IUnitOfWork Create(string userSelectedConnectionString)
{
return new MyUoW(new MyDataContext(userSelectedConnectionString),
_type1Repository, _type2Repository, _type3Repository,
_type4Repository, _type5Repository, _type6Repository);
}
With the kernel bindings I've defined, this causes the DataContext of the repositories to point where the kernel dictates, and the DataContext of the created UoW to point where the user asked for.
How can I pull this off without resorting to service locator? I need the repositories to have their DataContext injected not at app start-up, but after the user has selected a database. Is this where Ninject.Factory comes into play?
Argh.. did it again (finding answer shortly after posting in premature despair). What I wanted was the unit of work factory to actually create the repositories. So the answer is pretty simple: instead of injecting IRepository<T>, I created an interface IRepositoryFactory<T> and injected that instead:
public interface IRepositoryFactory<T> where T : class
{
IRepository<T> Create(DataContext context);
}
This way the Create method of MyUoWFactory taking the user-selected connection string could create only one context and pass it to all repository factories:
public MyUoWFactory(IRepositoryFactory<Type1> type1repoFactory, IRepositoryFactory<Type2> type2repoFactory,
IRepositoryFactory<Type3> type3repoFactory, IRepositoryFactory<Type4> type4repoFactory,
IRepositoryFactory<Type5> type5repoFactory, IRepositoryFactory<Type6> type6repoFactory)
{
_type1RepositoryFactory = type1repoFactory;
_type2RepositoryFactory = type2repoFactory;
_type3RepositoryFactory = type3repoFactory;
_type4RepositoryFactory = type4repoFactory;
_type5RepositoryFactory = type5repoFactory;
_type6RepositoryFactory = type6repoFactory;
}
public IUnitOfWork Create(string userSelectedConnectionString)
{
var context = new MyDataContext(userSelectedConnectionString)
return new MyUoW(context,
_type1RepositoryFactory.Create(context),
_type2RepositoryFactory.Create(context),
_type3RepositoryFactory.Create(context),
_type4RepositoryFactory.Create(context),
_type5RepositoryFactory.Create(context),
_type6RepositoryFactory.Create(context));
}
I am evaluating JOliver's EventStore library. In particular, I am trying to use RavenDB as the persistence engine for EventStore. EventStore comes with a plugin for this. NOTE: The database is empty with no indexes (other than the default ones).
In wiring up the store, I used the following:
var store = Wireup.Init()
.UsingRavenPersistence("EventStore", new DocumentObjectSerializer())
.Build();
However, when I run my program, I get an exception that indicates the "RavenCommitByRevisionRange" index could not be found.
In digging around the EventStore code, I think the problem happens to be that the RavenPersistenceEngine is not being initialized. The initialization code installs the needed indexes in the RavenDB server.
On the SQL server side of things, I noticed that the wiring code in the example project shows a call to an extension method called: "InitializeStorageEngine". This extension method is tied to the class "PersistenceWireup". However, the extension method I'm using to wire in RavenDB persistence returns the class "Wireup". So I wrapped part of my wireup code in a new PersistenceWireup instance, and was able to call ".InitializeStorageEngine()" like so:
var store = new PersistenceWireup(
Wireup.Init()
.UsingRavenPersistence("EventStore", new DocumentObjectSerializer()))
.InitializeStorageEngine()
.Build();
This works great! The RavenDB database now contained the necessary indexes.
So... My questions: Shouldn't ".UsingRavenPersistence(...)" return an instance of "PersistenceWireup" rather than simply "Wireup"? Or is there a better way to wire up RavenDB persistence in EventStore?
Hmmm. Well, I think that the reason raven doesn't implement PersistenceWireup is b/c that interface exposes ISerializer specific methods which the document store implementations don't use. We probably need to move the initialize to Wireup. I'll look into this.
However, I see that you're missing the dispatcher that will dispatch the event after storage. Was this intentional? If you're not planning on publishing from another enpoint, the add the Synchronous / Asynchronous dispatcher. The dispatcher is currently calling initialize.
Wireup.Init()
.UsingRavenPersistence("EventStore", new DocumentObjectSerializer())
.UsingSynchronousDispatcher()
.PublishTo(new DelegateMessagePublisher(c => PublishMessages(c))
.Build();
private IStoreEvents GetInitializedEventStore(IDispatchCommits bus)
{
return Wireup.Init()
.UsingRavenPersistence(BootStrapper.RavenDbEventStoreConnectionStringName)
.UsingAsynchronousDispatchScheduler(bus)
.Build();
}