Testing inserting record into mocking objects with NUnit Test

Topics: Writing modules
Dec 9, 2011 at 2:56 PM

Hi guys,

I've tried to create a unit test for a simple Insert record behaviour into a database. So I created this test case:

public class ContractServiceTests : DatabaseEnabledTestsBase
    {
        private IContractService _contractService;

        public override void Register(ContainerBuilder builder)
        {
            builder.RegisterType<ContractService>().As<IContractService>();
            builder.RegisterType<ClauseService>().As<IClauseService>();
            builder.RegisterAutoMocking(MockBehavior.Loose);
            var contractRepoMock = new Mock<IRepository<ContractRecord>>();
            builder.RegisterInstance(contractRepoMock.Object);
            builder.RegisterInstance(new Mock<IRepository<ClauseRecord>>().Object);
            builder.RegisterInstance(new Mock<IRepository<ContractClausesRecord>>().Object);
            
        }

        protected override IEnumerable<Type> DatabaseTypes
        {
            get
            {
                return new[] { 
                    typeof(ClauseRecord),
                    typeof(ContractRecord),
                    typeof(ContractClausesRecord)
                };
            }
        }

        public override void Init()
        {
            base.Init();
            _contractService = _container.Resolve<IContractService>();
        }

        [Test]
        public void ShouldBeAbleToInsertAndRetrieveContract()
        {
            _contractService.InsertContract(new ContractRecord
            {
                Name = "Sample Contract",
                CreateDate = DateTime.Now,
                ModifyDate = DateTime.Now,
            });

            var contractRepo = _container.Resolve<IRepository<ContractRecord>>();
            var contract = contractRepo.Table.Where(c => c.Id == 1).FirstOrDefault();
            Assert.That(contract.Name, Is.EqualTo("Sample Contract"));
        }
    }

For an unknown reason to me that there is no record is inserted into the Mock object. So my test failed of course. 

I'm wondering if the way I set up the test incorrectly or the actual code itself in the service class is wrong

Please let me know

Thanks in advance

Coordinator
Dec 9, 2011 at 6:06 PM

What does ContractService look like?

Dec 9, 2011 at 6:10 PM
bertrandleroy wrote:

What does ContractService look like?

Here is my Contract Service 

public class ContractService : IContractService
    {
        #region Variables
        private readonly IRepository<ContractRecord> _contractRepository;
        private readonly IRepository<ContractClausesRecord> _contractClauseRepository;
        private readonly IClauseService _clauseService;
        #endregion

        #region Constructor
        public ContractService(IRepository<ContractRecord> contractRepository, IClauseService clauseService,
            IRepository<ContractClausesRecord> contractClauseRepository)
        {
            _contractRepository = contractRepository;
            _clauseService = clauseService;
            _contractClauseRepository = contractClauseRepository;
        }
        #endregion

        #region Methods
        public ContractRecord GetContractById(int id)
        {
            if (id <= 0)
            {
                throw new ArgumentNullException();
            }
            var contract = _contractRepository.Table.Where(c => c.Id == id).FirstOrDefault();
            return contract;
        }

        public IQueryable<ContractRecord> GetAllContracts()
        {
            return _contractRepository.Table;
        }

        public IQueryable<ClauseRecord> GetAllClausesByContractId(int id)
        {
            var allClauses = from clause in _clauseService.GetAllClauses()
                             join contractClause in _contractClauseRepository.Table on clause.Id equals contractClause.Clause.Id
                             where contractClause.Contract.Id == id
                             select clause;

            return allClauses;
        }

        public void InsertContract(ContractRecord contract)
        {
            if (contract == null)
            {
                throw new ArgumentNullException();
            }

            _contractRepository.Create(contract);
        }

        public void UpdateContract(ContractRecord contract)
        {
            if (contract == null)
            {
                throw new ArgumentNullException();
            }

            _contractRepository.Update(contract);
        }

        public void DeleteContractById(int id)
        {
            if (id <= 0)
            {
                throw new ArgumentNullException();
            }

            var contract = _contractRepository.Table.Where(c => c.Id == id).FirstOrDefault();
            if (contract == null)
            {
                throw new ArgumentNullException();
            }
            _contractRepository.Delete(contract);
        }
        #endregion
    }

Is the way I set up the test case correct? 

Coordinator
Dec 9, 2011 at 6:59 PM

That looks fine. Did you try to step into all this from a debugger?

Dec 9, 2011 at 7:06 PM
bertrandleroy wrote:

That looks fine. Did you try to step into all this from a debugger?

Yes I did.

The inserting step returns no error. However, there is no record in the mock repository when I tried to retrieve the new record to verify. My guess could be the binding of mock repository are not correct. The inserting step could be in one mock repository and the retrieve is from a different one? Somewhere between these two lines are not right: 

	_contractService.InsertContract(new ContractRecord
            {
                Name = "Sample Contract",
                CreateDate = DateTime.Now,
                ModifyDate = DateTime.Now,
            });

        var contractRepo = _container.Resolve<IRepository<ContractRecord>>();
Please let me know if you find out my mistakes.
Thanks in advance

Coordinator
Dec 9, 2011 at 7:17 PM

I can't spot it like that :) Next thing I would do is put your code side by side with another existing similar test case that passes and try to spot the difference.

Dec 9, 2011 at 7:23 PM
bertrandleroy wrote:

I can't spot it like that :) Next thing I would do is put your code side by side with another existing similar test case that passes and try to spot the difference.

I understand your point of view :). I did compare my code with MembershipServiceTests.cs which comes with Orchard

[TestFixture]
    public class MembershipServiceTests {
        private IMembershipService _membershipService;
        private ISessionFactory _sessionFactory;
        private ISession _session;
        private IContainer _container;


        public class TestSessionLocator : ISessionLocator {
            private readonly ISession _session;

            public TestSessionLocator(ISession session) {
                _session = session;
            }

            public ISession For(Type entityType) {
                return _session;
            }
        }

        [TestFixtureSetUp]
        public void InitFixture() {
            var databaseFileName = System.IO.Path.GetTempFileName();
            _sessionFactory = DataUtility.CreateSessionFactory(
                databaseFileName,
                typeof(UserPartRecord),
                typeof(ContentItemVersionRecord),
                typeof(ContentItemRecord),
                typeof(ContentTypeRecord));
        }

        [TestFixtureTearDown]
        public void TermFixture() {

        }

        [SetUp]
        public void Init() {
            var builder = new ContainerBuilder();
            //builder.RegisterModule(new ImplicitCollectionSupportModule());
            builder.RegisterType<MembershipService>().As<IMembershipService>();
            builder.RegisterType<DefaultContentQuery>().As<IContentQuery>();
            builder.RegisterType<DefaultContentManager>().As<IContentManager>();
            builder.RegisterType(typeof(SettingsFormatter))
                .As(typeof(IMapper<XElement, SettingsDictionary>))
                .As(typeof(IMapper<SettingsDictionary, XElement>));
            builder.RegisterType<ContentDefinitionManager>().As<IContentDefinitionManager>();
            builder.RegisterType<DefaultContentManagerSession>().As<IContentManagerSession>();
            builder.RegisterType<UserPartHandler>().As<IContentHandler>();
            builder.RegisterType<StubWorkContextAccessor>().As<IWorkContextAccessor>();
            builder.RegisterType<OrchardServices>().As<IOrchardServices>();
            builder.RegisterAutoMocking(MockBehavior.Loose);
            builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IRepository<>));
            builder.RegisterInstance(new Mock<IMessageEventHandler>().Object);
            builder.RegisterType<DefaultMessageManager>().As<IMessageManager>();
            builder.RegisterType<DefaultShapeTableManager>().As<IShapeTableManager>();
            builder.RegisterType<DefaultShapeFactory>().As<IShapeFactory>();
            builder.RegisterType<StubExtensionManager>().As<IExtensionManager>();
            builder.RegisterType<DefaultContentDisplay>().As<IContentDisplay>();

            _session = _sessionFactory.OpenSession();
            builder.RegisterInstance(new TestSessionLocator(_session)).As<ISessionLocator>();
            _container = builder.Build();
            _membershipService = _container.Resolve<IMembershipService>();
        }

        [Test]
        public void CreateUserShouldAllocateModelAndCreateRecords() {
            var user = _membershipService.CreateUser(new CreateUserParams("a", "b", "c", null, null, true));
            Assert.That(user.UserName, Is.EqualTo("a"));
            Assert.That(user.Email, Is.EqualTo("c"));
        }
    }

My test cases are based on this class a lot. I can run other test cases no problem, except for the inserting behaviour. The Updating behaviour on the other hand works fine.

If you spot any major differences, please let me know. But now at least I know it's not come from stupid mistakes I made.

Thanks

Coordinator
Dec 9, 2011 at 7:36 PM

Did you check that your service and the test have the same instance of the mock repo?

Dec 9, 2011 at 7:54 PM
bertrandleroy wrote:

Did you check that your service and the test have the same instance of the mock repo?

To be honest, I'm a newbie in writing test with Moq and NUnit test.

This is what I tried to do to ensure the test have the same instance of mock repo

[Test]
        public void ShouldBeAbleToInsertAndRetrieveContract()
        {
            var newContract = new ContractRecord
            {
                Name = "Sample Contract",
                CreateDate = DateTime.Now,
                ModifyDate = DateTime.Now,
            };
            var contractRepoMock = _container.Resolve<Mock<IRepository<ContractRecord>>>();
            var contractRepo = contractRepoMock.Object;
            var contractClauseRepo = _container.Resolve<Mock<IRepository<ContractClausesRecord>>>().Object;
            var clauseService = _container.Resolve<IClauseService>();

            _contractService = new ContractService(contractRepo, clauseService, contractClauseRepo);
            _contractService.InsertContract(newContract);

            
            var contract = contractRepo.Table.Where(c => c.Id == 1).FirstOrDefault();
            Assert.That(contract.Name, Is.EqualTo("Sample Contract"));
        }

In the debugger, the Castle.Proxies.IRepository are the same for ContracRecord. I don't know if that means something. Just throw it out there.

Let me know

Tri

Coordinator
Dec 9, 2011 at 10:00 PM

And... I haven't done that in a while so I don't remember how you're supposed to mock the repository. I don't see where the behavior of the mock is defined. It seems like if this is all you define, it's just a black hole. Do other similar tests do it this way as well?

Dec 12, 2011 at 3:38 PM
bertrandleroy wrote:

And... I haven't done that in a while so I don't remember how you're supposed to mock the repository. I don't see where the behavior of the mock is defined. It seems like if this is all you define, it's just a black hole. Do other similar tests do it this way as well?

Thanks for your help. Also sorry for the late response (it was the weekend). The mock need to be setup for the inserting behavior. I set up mocks for retrieving and updating. They worked perfectly fine. My knowledge about mocking is still very limited. I will look deeply into inserting behavior for mocking and see what I can to set up those behaviors.