Search code examples
unit-testingravendbmspecmachine.fakes

Using Machine.Fakes unit testing with RavenDB EmbeddableDocumentStore


I normally mock IDocumentSession in my MSpec with Machine.Fakes, which the RavenDB guys don't like. How do I use the EmbeddableDocumentStore with Machine.Fakes ?


Solution

  • gist: https://gist.github.com/JasonMore/5345697

    Hooking RavenDB InMemory to Machine.Fakes

    public class RavenInMemorySlowRunner
    {
        public class NoStaleQueriesAllowed : IDocumentQueryListener
        {
            public void BeforeQueryExecuted(IDocumentQueryCustomization queryCustomization)
            {
                queryCustomization.WaitForNonStaleResults();
            }
        }
    
        public class AllDocumentsById : AbstractIndexCreationTask
        {
            public override IndexDefinition CreateIndexDefinition()
            {
                return new IndexDefinition
                {
                    Name = "AllDocumentsById",
                    Map = "from doc in docs let DocId = doc[\"@metadata\"][\"@id\"] select new {DocId};"
                };
            }
        }
    
        public static EmbeddableDocumentStore Store { get; set; }
        public static IDocumentSession Session { get; set; }
    
        OnEstablish context = fakeAccessor =>
        {
            fakeAccessor.Configure(x => x.For<IDocumentSession>().Use(() =>
            {
                if (Store == null)
                {
                    Store = new EmbeddableDocumentStore { RunInMemory = true };
                    Store.RegisterListener(new NoStaleQueriesAllowed());
                    Store.Initialize();
    
                    // RegisterServicesWithNinject is in the project where the indexes live
                    IndexCreation.CreateIndexes(typeof(RegisterServicesWithNinject).Assembly, Store);
                    IndexCreation.CreateIndexes(typeof(RavenInMemorySlowRunner).Assembly, Store);
                }
    
                if (Session == null)
                {
                    Session = Store.OpenSession();
                }
    
                return Session;
            }));
    
        };
    
        OnCleanup subject = subject =>
        {
            Session.Advanced.DocumentStore.DatabaseCommands.DeleteByIndex("AllDocumentsById", new IndexQuery());
            Session.SaveChanges();
            Session.Dispose();
        };
    }
    

    The Test

    public class CurrentSiteModelServiceSpecs : WithSubject<CurrentSiteModelService>
    {
        Establish that = () =>
        {
            // use the raven in memory runner since 
            // we are using lots of raven magic in this service
            With(new RavenInMemorySlowRunner());
        };
    }
    
    /// <summary>
    /// Determine Site Model for Dev
    /// </summary>
    public class When_Determining_SiteModel_for_dev : CurrentSiteModelServiceSpecs
    {
        public static SiteViewModel _siteViewModelResult;
        public static IHttpCookie _cookie;
    
        Because of = () =>
            _siteViewModelResult = Subject.DetermineSiteModelForDevEnvironment();
    }
    
    public class And_Cookie_not_set : When_Determining_SiteModel_for_dev
    {
        It returns_null = () =>
            _siteViewModelResult.ShouldBeNull();
    }
    
    public class And_Cookie_set : When_Determining_SiteModel_for_dev
    {
    
        Establish that = () =>
        {
            _cookie = An<IHttpCookie>();
            _cookie.Value = "site/123";
    
            The<ICookieService>()
                .WhenToldTo(x => x.GetCookie(".CMS3DevSite"))
                .Return(_cookie);
    
            var site1 =  new SiteModel{ Id = "site/123", HostName = "foo" };
            var site2 =  new SiteModel{ Id = "site/456", HostName = "bar" };
    
            The<IDocumentSession>().Store(site1);
            The<IDocumentSession>().Store(site2);
            The<IDocumentSession>().SaveChanges();
    
        };
    
        It loads_site = () =>
            _siteViewModelResult.HostName.ShouldEqual("foo");
    }
    
    public class And_Cookie_set_but_site_does_not_exist : When_Determining_SiteModel_for_dev
    {
        Establish that = () =>
        {
            _cookie = An<IHttpCookie>();
            _cookie.Value = "site/123";
    
            The<ICookieService>()
                .WhenToldTo(x => x.GetCookie(".CMS3DevSite"))
                .Return(_cookie);
        };
    
        It returns_null = () =>
            _siteViewModelResult.ShouldBeNull();
    }
    

    The Service I'm testing

    public interface ICurrentSiteModelService { RedirectToResult SetSiteModel(string path, Uri url); }

    public class CurrentSiteModelService : ICurrentSiteModelService
    {
        readonly IDocumentSession _documentSession;
        readonly ICookieService _cookieService;
    
        public CurrentSiteModelService(
            IDocumentSession documentSession,
            ICookieService cookieService)
        {
            _documentSession = documentSession;
            _cookieService = cookieService;
        }
    
    
    // cruft removed here
    
        // load site in dev mode based on cookie.
        internal SiteViewModel DetermineSiteModelForDevEnvironment()
        {
            var cookie = _cookieService.GetCookie(".CMS3DevSite");
            if (cookie != null && !String.IsNullOrEmpty(cookie.Value))
            {
                SiteViewModel site = _documentSession.
                    Query<SiteViewModel, SiteViewIndex>()
                    .Where(s => s.Id == cookie.Value)
                    .AsProjection<SiteViewModel>()
                    .FirstOrDefault();
    
                if (site != null)
                {
                    return site;
                }
            }
    
            return null;
        }
    }