Sinto que estou perdendo algo realmente óbvio aqui. Eu tenho classes que exigem a injeção de opções usando o padrão .Net Core IOptions (?). Quando vou ao teste de unidade dessa classe, quero zombar de várias versões das opções para validar a funcionalidade da classe. Alguém sabe como simular / instanciar / preencher corretamente IOptions fora da classe Startup?
Aqui estão alguns exemplos das classes com as quais estou trabalhando:
Modelo de configurações / opções
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace OptionsSample.Models
{
public class SampleOptions
{
public string FirstSetting { get; set; }
public int SecondSetting { get; set; }
}
}
Classe a ser testada que usa as Configurações:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using OptionsSample.Models
using System.Net.Http;
using Microsoft.Extensions.Options;
using System.IO;
using Microsoft.AspNetCore.Http;
using System.Xml.Linq;
using Newtonsoft.Json;
using System.Dynamic;
using Microsoft.Extensions.Logging;
namespace OptionsSample.Repositories
{
public class SampleRepo : ISampleRepo
{
private SampleOptions _options;
private ILogger<AzureStorageQueuePassthru> _logger;
public SampleRepo(IOptions<SampleOptions> options)
{
_options = options.Value;
}
public async Task Get()
{
}
}
}
Teste de unidade em uma montagem diferente das outras classes:
using OptionsSample.Repositories;
using OptionsSample.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Xunit;
using Microsoft.Extensions.Logging;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
namespace OptionsSample.Repositories.Tests
{
public class SampleRepoTests
{
private IOptions<SampleOptions> _options;
private SampleRepo _sampleRepo;
public SampleRepoTests()
{
//Not sure how to populate IOptions<SampleOptions> here
_options = options;
_sampleRepo = new SampleRepo(_options);
}
}
}
IOptions<T>
você só precisa zombarValue
para retornar a classe que desejaRespostas:
Você precisa criar e preencher manualmente um
IOptions<SampleOptions>
objeto. Você pode fazer isso através daMicrosoft.Extensions.Options.Options
classe auxiliar. Por exemplo:Você pode simplificar um pouco para:
Obviamente, isso não é muito útil como é. Você realmente precisará criar e preencher um objeto SampleOptions e passá-lo para o método Create.
fonte
new OptionsWrapper<SampleOptions>(new SampleOptions());
todos os lugaresSe você pretende usar o Mocking Framework conforme indicado por @TSeng no comentário, precisará adicionar a seguinte dependência no seu arquivo project.json.
Depois que a dependência é restaurada, o uso da estrutura MOQ é tão simples quanto criar uma instância da classe SampleOptions e, como mencionado, atribuí-la ao Valor.
Aqui está um resumo de código como seria.
Depois que a simulação é configurada, agora você pode passar o objeto de simulação para o contratante como
HTH.
Para sua informação, eu tenho um repositório git que descreve essas duas abordagens no Github / patvin80
fonte
Você pode evitar o uso de MOQ. Use em seu arquivo de configuração .json de testes. Um arquivo para muitos arquivos de classe de teste. Vai ser bom usar
ConfigurationBuilder
neste caso.Exemplo de appsetting.json
Exemplo de classe de mapeamento de configurações:
Exemplo de serviço necessário para testar:
Classe de teste NUnit:
fonte
Classe dada
Person
que depende doPersonSettings
seguinte:IOptions<PersonSettings>
pode ser ridicularizado ePerson
pode ser testado da seguinte maneira:Para injetar
IOptions<PersonSettings>
emPerson
vez de passá-lo explicitamente para o ctor, use este código:fonte
Você sempre pode criar suas opções via Options.Create () e simplesmente usar o AutoMocker.Use (options) antes de criar a instância simulada do repositório que está testando. O uso do AutoMocker.CreateInstance <> () facilita a criação de instâncias sem passar manualmente os parâmetros
Eu mudei um pouco o SampleRepo para poder reproduzir o comportamento que acho que você deseja alcançar.
fonte
Aqui está outra maneira fácil que não precisa do Mock, mas usa o OptionsWrapper:
fonte
Para meus testes de sistema e integração, prefiro ter uma cópia / link do meu arquivo de configuração dentro do projeto de teste. E então eu uso o ConfigurationBuilder para obter as opções.
Dessa forma, eu posso usar a configuração em qualquer lugar dentro do meu TestProject. Para testes de unidade, prefiro usar o MOQ como o patvin80 descrito.
fonte
Concorde com Aleha que o uso de um arquivo de configuração testSettings.json provavelmente é melhor. E então, em vez de injetar a IOption, você pode simplesmente injetar as SampleOptions reais no construtor de sua classe. Ao testar a classe por unidade, você pode fazer o seguinte em um equipamento ou novamente apenas no construtor da classe de teste:
fonte