Pergunta

Um aplicativo de banco de dados no qual estou trabalhando atualmente armazena todos os tipos de configurações no banco de dados.A maioria dessas configurações existe para personalizar certas regras de negócios, mas também há outras coisas.

O aplicativo contém objetos que realizam especificamente uma determinada tarefa, por exemplo, um determinado cálculo complicado.Esses objetos que não são da UI são testados em unidade, mas também precisam de acesso a muitas dessas configurações globais.A forma como implementamos isso agora é fornecendo aos objetos propriedades que são preenchidas pelo Application Controller em tempo de execução.Ao testar, criamos os objetos no teste e preenchemos os valores para teste (não do banco de dados).

Isso funciona melhor, em qualquer caso, muito melhor do que fazer com que todos esses objetos precisem de alguma Configurações object --- isso, é claro, torna efetivamente o teste de unidade impossível :) A desvantagem pode ser que às vezes você precisa definir uma dúzia de propriedades ou deixar essas propriedades 'filtrarem-se' em subobjetos.

Então a questão geral é:como você fornece acesso às configurações globais de aplicativos em seus projetos, sem a necessidade de variáveis ​​globais, e ainda sendo capaz de testar seu código?Este deve ser um problema que já foi resolvido centenas de vezes...

(Observação:Não sou um programador muito experiente, como você deve ter notado;mas adoro aprender!E claro, já pesquisei sobre esse assunto, mas estou realmente procurando algumas experiências em primeira mão)

Foi útil?

Solução

Você pode usar padrão de Martin Fowlers ServiceLocator. Em php poderia ficar assim:

class ServiceLocator {
  private static $soleInstance;
  private $globalSettings;

  public static function load($locator) {
    self::$soleInstance = $locator;
  }

  public static function globalSettings() {
    if (!isset(self::$soleInstance->globalSettings)) {
      self::$soleInstance->setGlobalSettings(new GlobalSettings());
    }
    return self::$soleInstance->globalSettings;
  }
}

O seu código de produção, em seguida, inicializa o localizador de serviço como este:

ServiceLocator::load(new ServiceLocator());

Em seu teste-code, você inserir seus mock-definições como esta:

ServiceLocator s = new ServiceLocator();
s->setGlobalSettings(new MockGlobalSettings());
ServiceLocator::load(s);

É um repositório para singletons que podem ser trocados para fins de teste.

Outras dicas

Eu gosto de modelar o meu acesso à configuração fora do padrão Service Locator. Isso me dá um único ponto de obter qualquer valor de configuração que eu preciso e, colocando-o fora do aplicativo em uma biblioteca separada, permite a reutilização ea capacidade de teste. Aqui está um código de exemplo, não estou certo de que língua você está usando, mas eu escrevi em C #.

Primeiro eu criar uma classe genérica que os modelos é que o meu item de configuração.

public class ConfigurationItem<T>
{
    private T item;

    public ConfigurationItem(T item)
    {
        this.item = item;
    }

    public T GetValue()
    {
        return item;
    }
}

Então eu criar uma classe que expõe public static readonly variáveis ??para o item de configuração. Aqui eu estou apenas lendo as ConnectionStringSettings a partir de um arquivo de configuração, que é apenas xml. É claro que para mais itens, você pode ler os valores de qualquer fonte.

public class ConfigurationItems
{
    public static ConfigurationItem<ConnectionStringSettings> ConnectionSettings = new ConfigurationItem<ConnectionStringSettings>(RetrieveConnectionString());

    private static ConnectionStringSettings RetrieveConnectionString()
    {
        // In .Net, we store our connection string in the application/web config file.
        // We can access those values through the ConfigurationManager class.
        return ConfigurationManager.ConnectionStrings[ConfigurationManager.AppSettings["ConnectionKey"]];
    }
}

Então, quando eu preciso de um item de configuração para uso, eu chamá-lo assim:

ConfigurationItems.ConnectionSettings.GetValue();

E vai me devolver um valor seguro tipo, que pode, então, cache ou fazer o que quiser com ele.

Aqui está um teste de exemplo:

[TestFixture]
public class ConfigurationItemsTest
{
    [Test]
    public void ShouldBeAbleToAccessConnectionStringSettings()
    {
        ConnectionStringSettings item = ConfigurationItems.ConnectionSettings.GetValue();
        Assert.IsNotNull(item);
    }
}

Espero que isso ajude.

Normalmente, isso é feito por um arquivo ini ou arquivo de configuração XML. Então você só tem uma classe que lê a configuração quando neeed.

.NET tem esta embutido com as classes ConfigurationManager, mas é muito fácil de implementar, basta ler arquivos de texto ou XML carga no DOM ou analisá-los com a mão no código.

Tendo arquivos de configuração no banco de dados é ok, mas não amarrá-lo ao banco de dados, e cria uma dependência extra para o seu aplicativo que arquivos ini / xml resolver.

Eu fiz isso:

public class MySettings
{
    public static double Setting1
        { get { return SettingsCache.Instance.GetDouble("Setting1"); } }

    public static string Setting2
        { get { return SettingsCache.Instance.GetString("Setting2"); } }
}

Eu coloquei isso em um módulo de infra-estrutura separada para remover quaisquer problemas com dependências circulares.
Fazer isso não estou vinculado a qualquer método de configuração específica, e não têm cordas que funcionam estragos no meu código aplicações.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top