Code Monkey home page Code Monkey logo

Comments (6)

mehdime avatar mehdime commented on July 17, 2024 4

Hi rosdi,

This is the right place to ask since there are no other places for these sort of questions :)

I'm assuming that you followed Microsoft's guidance to create your stub DbContext and DbSet instances.

You'd now like to get DbContextScope to return these instead of the real instances. This is actually very easy (or I think it is anyway, I haven't actually tried it yet :) )

You'll note that the DbContextScope constructor takes an optional IDbContextFactory instance. The IDbContextFactory was created to do precisely what you're trying to do: it lets you control the creation of the DbContext instances, allowing you to e.g. substitute them with a stub implementation.

So in your unit test, simply implement the IDbContextFactory interface and get it to return your stub DbContext instance. Alternatively, you can of course use a mocking library like Moq to do that for you. Then, provide this "stub DbContext factory" to your DbContextScope and you're all done.

from dbcontextscope.

rosdi avatar rosdi commented on July 17, 2024

Nevermind.. I will just do integration test instead... and this is not even a proper place to ask this question anyway. Sorry about that.

from dbcontextscope.

pkirillov avatar pkirillov commented on July 17, 2024

I had the same question last week for myself. Ended up with this kind of fake. Not fully implemented obviously, but enough for now.

Note: my real services are using AmbientDbContextLocator, but within unit tests I don't need it, that's why IDbContextCollection DbContexts is not implemented.

    /// <summary>
    /// Represents fake DbContextScope for services unit testing
    /// </summary>
    public class FakeDbContextScope : IDbContextScope
    {
        private bool _disposed;
        private int _saveChangesCount;

        public FakeDbContextScope()
        {
            _disposed = false;
            _saveChangesCount = 0;
        }

        public int SaveChanges()
        {
            _saveChangesCount++;
            return 0;
        }

        public Task<int> SaveChangesAsync()
        {
            throw new NotImplementedException("SaveChangesAsync() is not implemented within FakeDbContextScope");
        }

        public Task<int> SaveChangesAsync(CancellationToken cancelToken)
        {
            throw new NotImplementedException("SaveChangesAsync(cancelToken) is not implemented within FakeDbContextScope");
        }

        public void RefreshEntitiesInParentScope(IEnumerable entities)
        {
            throw new NotImplementedException("RefreshEntitiesInParentScope(entities) is not implemented within FakeDbContextScope");
        }

        public Task RefreshEntitiesInParentScopeAsync(IEnumerable entities)
        {
            throw new NotImplementedException("RefreshEntitiesInParentScopeAsync(entities) is not implemented within FakeDbContextScope");
        }

        public IDbContextCollection DbContexts
        {
            get
            {
                throw new NotImplementedException("IDbContextCollection() is not implemented within FakeDbContextScope");
            }
        }

        public bool Disposed
        {
            get
            {
                return _disposed;
            }
        }

        public void Dispose()
        {
            _disposed = true;
        }
    }

from dbcontextscope.

rosdi avatar rosdi commented on July 17, 2024

I got it to work... thanks to both of you.. from now on I don't see any reason NOT to use DbContextScope for my future projects... cheers..

from dbcontextscope.

tomtommorrow avatar tomtommorrow commented on July 17, 2024

Hi. I followed the guide you referenced above for creating stub DbContext and DbSet instances but I am still having trouble mocking a service similar(really the exact same) to the 'SendWelcomeEmail' in the UserEmailService examples. I am injecting IDbContextScopeFactory (using autofac) just like the UserEmailService example(no other dependencies) but I can't figure out how to mock the service. I am using moq. Any help would be greatly appreciated. I love the work you have done, it is making all of my projects so much easier. Thanks ahead.

         public async Task Test_vendor_async_service()
       {
        //shortened for brevity
        var data = new List<Vendor>();

        var mockSet = new Mock<DbSet<Vendor>>();
        mockSet.As<IDbAsyncEnumerable<Vendor>>()
            .Setup(m => m.GetAsyncEnumerator())
            .Returns(new TestDbAsyncEnumerator<Vendor>(data.GetEnumerator()));

        mockSet.As<IQueryable<Vendor>>()
            .Setup(m => m.Provider)
            .Returns(new TestDbAsyncQueryProvider<Vendor>(data.Provider));

        mockSet.As<IQueryable<Vendor>>().Setup(m => m.Expression).Returns(data.Expression);
        mockSet.As<IQueryable<Vendor>>().Setup(m => m.ElementType).Returns(data.ElementType);
        mockSet.As<IQueryable<Vendor>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());

        //this is where I am not so sure what needs to be done.
        var mockFactory = new Mock<IDbContextScopeFactory>();
        mockFactory.As<MyContext>()
            .Setup(c => c.Vendors).Returns(mockSet.Object);

        //I can't really pass in the mockfactory because it of type Mock<T>
        //confused
        var service = new VendorsService(mockFactory);
        var vendors = await service.GetAllAsync().ConfigureAwait(false);

        Assert.AreEqual(3, vendors.Count);
        Assert.AreEqual("AAA", vendors[0].BusinessName);
        Assert.AreEqual("BBB", vendors[1].BusinessName);
        Assert.AreEqual("ZZZ", vendors[2].BusinessName);
    }

from dbcontextscope.

bmosca avatar bmosca commented on July 17, 2024

Hi, I've been working around the DbContextScope which is working fine however when it comes to Unit Testing I have to say I am a bit confused about how I should use the libraries in order to unit test a MVC application.
I am trying to call the method GetScanDefinitions() and assert the objects retrieved with my predefined mockset.

This is my Unit Test class:

public class UnitScanDefinitionsControllerTest
 {   
 private CrawlerContext _dbEntities;
     private readonly ICrawlerRepository _crawlerRepository;
     private IScanDefinitionService _scanDefinitionService;

     public UnitScanDefinitionsControllerTest()
     {
         IAmbientDbContextLocator ambientDbContextLocator = new AmbientDbContextLocator();
         _crawlerRepository = new CrawlerRepository(ambientDbContextLocator);
     }

     [Fact]
     public async Task ScanDefinitionView()
     {
         var data = new List<ScanDefinition>
         {
             new ScanDefinition { Name = "AAA" },
             new ScanDefinition { Name = "BBB" },
             new ScanDefinition { Name = "CCC" },

         }.AsQueryable();


         var mockSet = new Mock<DbSet<ScanDefinition>>();
         mockSet.As<IDbAsyncEnumerable<ScanDefinition>>()
             .Setup(m => m.GetAsyncEnumerator())
             .Returns(new DbAsyncEnumerator<ScanDefinition>(data.GetEnumerator()));

         mockSet.As<IQueryable<ScanDefinition>>()
             .Setup(m => m.Provider)
             .Returns(new DbAsyncQueryProvider<ScanDefinition>(data.Provider));

         mockSet.As<IQueryable<ScanDefinition>>().Setup(m => m.Expression).Returns(data.Expression);
         mockSet.As<IQueryable<ScanDefinition>>().Setup(m => m.ElementType).Returns(data.ElementType);
         mockSet.As<IQueryable<ScanDefinition>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());

         var mockFactory = new Mock<IDbContextFactory>();
         mockFactory.Setup(c => c.CreateDbContext<CrawlerContext>()).Returns(_dbEntities);

         _dbContextFactory = mockFactory.Object;

         // Setup DbContextScopeFactory to use mocked context
         _mockContextScope = new DbContextScopeFactory(_dbContextFactory);
         _scanDefinitionService = new ScanDefinitionService(_mockContextScope, _crawlerRepository);

         var scanDefinitions = await _scanDefinitionService.GetScanDefinitions().ToListAsync();

         Assert.Equal(3, scanDefinitions.Count);
         Assert.Equal("AAA", scanDefinitions[0].Name);
         Assert.Equal("BBB", scanDefinitions[1].Name);
         Assert.Equal("ZZZ", scanDefinitions[2].Name);
     }
 }

The Service Layer looks like this:

public class ScanDefinitionService : IScanDefinitionService
    {
        private readonly IDbContextScopeFactory _dbContextScopeFactory;
        private readonly ICrawlerRepository _crawlerRepository;

        public ScanDefinitionService(IDbContextScopeFactory dbContextScopeFactory, ICrawlerRepository context)
        {
            _dbContextScopeFactory = dbContextScopeFactory;
            _crawlerRepository = context;
        }

        public IQueryable<ScanDefinition> GetScanDefinitions()
        {
            using (_dbContextScopeFactory.CreateReadOnly())
            {
                return _crawlerRepository.GetScanDefinitions();
            }
        }
	}

And finally the Repository Layer:

public class CrawlerRepository : ICrawlerRepository

    {
        private readonly IAmbientDbContextLocator _ambientDbContextLocator;

        private CrawlerContext DbContext
        {
            get
            {
                var dbContext = _ambientDbContextLocator.Get<CrawlerContext>();

                if (dbContext == null)
                    throw new InvalidOperationException("Db Context Error message");

                return dbContext;
            }
        }

        public CrawlerRepository(IAmbientDbContextLocator ambientDbContextLocator)
        {
            if (ambientDbContextLocator == null) throw new ArgumentNullException("ambientDbContextLocator");
            _ambientDbContextLocator = ambientDbContextLocator;
        }
	
	    
		public IQueryable<ScanDefinition> GetScanDefinitions()
        {
            return DbContext.ScanDefinitions  **<--- TEST FAILS HERE; Message: System.NullReferenceException : Object reference not set to an instance of an object.**
                .Include(sd => sd.ScanBases)
                .Include(sd => sd.ScanDefinitionFileTypes)
                .Include(sd => sd.ScanDefinitionRuleDefinitions);
        }
	}

Any help would be much appreciated.

from dbcontextscope.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.