Внедрить базовый контекст Entity Framework в репозиторий с помощью ServiceStack при модульном тестировании - PullRequest
0 голосов
/ 10 декабря 2018

У меня есть класс репозитория

public class PersonRepository : IPersonRepository
{
    private DataContext _context;

    public PersonRepository(DataContext context)
    {
        _context = context;
    }

    public List<PersonDto> Fetch() ......
}

У меня есть ServiceStack PersonsService

public class PersonsServices : Service
{
    private IPersonsRepository _personRepo;

    public PersonsServices(IPersonsRepository personRepository)
    {
        _personRepo = personRepository;
    }

    public object Any(GetPersons request)
    {
        return new GetPersonssResponse
        {
            Results = _personsRepo.Fetch()
        };
    }
}

Мой код отлично работает в приложении ServiceStack, так как DataContext вводится .Net Coreкак настроено в методе AddDbContext в Startup.cs

services.AddDbContext<DataContext>(x => x
    .UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

Как мне сделать это в модульном тесте в сочетании с ServiceStack и использованием .Net Core Entity Framework?

Мне нужно что-то эквивалентноев AddDbContext здесь.В конечном итоге моя цель - создать модульные тесты, которые используют контекст в памяти или SQLite, но сохраняют тот же код хранилища.

РЕДАКТИРОВАТЬ: Вот как выглядит мой модульный тест до сих пор.

[TestFixture]
    public class PersonTest
    {
        private ServiceStackHost appHost;

        [SetUp]
        public void TestFixtureSetUp()
        {
            appHost = new BasicAppHost().Init();
            var container = appHost.Container;

            IConfigurationRoot configuration = new ConfigurationBuilder()
                   .SetBasePath(Directory.GetCurrentDirectory())
                   .AddJsonFile("appsettings.json")
                   .Build();

            var optionsBuilder = new DbContextOptionsBuilder<DataContext>();
            optionsBuilder
                .UseSqlite(configuration.GetConnectionString("DefaultConnection"));

// КАК ПОЛУЧИТЬ SERVICESTACK / FUNQ, чтобы РАЗРЕШИТЬ DataContext В Хранилище ???

            **container.Register<IDataContext>(i => new DataContext(optionsBuilder.Options)).ReusedWithin(ReuseScope.Request);**
            container.RegisterAutoWiredAs<PersonRepository, IPersonRepository>();

        }

        [Test]
        public async Task GetPersons()
        {
            var service = appHost.Container.Resolve<PersonsServices>();

            var response = await service.Any(new GetPersons { });
            var results = (GetPersonsResponse)response;

            Assert.That(1 == 1);
        }

        [TearDown]
        public void TestFixtureTearDown()
        {
            appHost.Dispose();
        }
    }

1 Ответ

0 голосов
/ 10 декабря 2018

Эта документация по Модульное тестирование .NET Core EF показывает, как можно создать InCon Data DataContext, который затем можно вставить в конструктор служб:

var options = new DbContextOptionsBuilder<BloggingContext>()
    .UseInMemoryDatabase(databaseName: "Add_writes_to_database")
    .Options;

// Run the test against one instance of the context
using (var context = new BloggingContext(options))
{
    var service = new BlogService(context);
}

Таким образом, вы можете передатьв DataContext и репозитории в вашем Сервисе:

using (var service = new PersonsServices(new PersonRepository(new DataContext(...))))
{
    var response = service.Any(new GetPersons { });
}

Или зарегистрируйте EF DataContext в IOC Funq:

container.Register<DataContext>(i => new DataContext(optionsBuilder.Options));
container.RegisterAutoWiredAs<PersonRepository, IPersonRepository>();

//...
using (var service = appHost.Container.Resolve<PersonsServices>())
{
}

Tips

  • Что вам необходимо для регистрациичтобы быть точным типом, который разрешается, например, поскольку PersonRepository принимает DataContext, вы должны зарегистрировать DataContext, а не IDataContext.
  • Не используйте область запросов вне HTTP-запроса, вы можете использовать временный или одноэлементный, поскольку в модульном тесте есть только один поток.
  • Если вы собираетесь вызывать вашСпособы обслуживания напрямую, вы также можете указать тип в вашем методе обслуживания.

Например:

public GetPersonsResponse Any(GetPersons request) => 
    new GetPersonsResponse {
        Results = _personsRepo.Fetch()
    };

, что позволит избежать приведения к ответу в вашем модульном тесте (которыйневерно в приведенном примере, поскольку он пытается ожидать синхронного метода, возвращающего объект).Указание типа ответа или object не влияет на ServiceStack

Если вы используете базу данных In Memory, рассмотрите возможность создания интеграционных тестов вместо того, чтобы использовать AppSelfHostBase, что для .NET Core находится в пакете ServiceStack.Kestrel .Вы можете переопределить ConfigureServices() для регистрации зависимостей в IOC .NET Core.

...