Desenvolvimento de uma equipe para consultar dados do banco de dados - parte 4, concluindo

Esta é uma continuação da história que começou aqui e continuou aqui e aqui .


Na última parte, escrevi um teste de integração demonstrando o processo de inicialização e execução de um conjunto completo de manipuladores que extraem dados de um banco de dados. Mas como pode demorar muito para escrever esse teste e executá-lo, é necessário codificar não apenas o manipulador, mas também as regras de configuração para todas as consultas necessárias ao banco de dados, hoje decidi implementar sua versão modular, projetada para configurar e executar tudo um manipulador. Este teste é assim:


describe('requestHandler', () => { const createStore = require('redux').createStore; const reducers = require('../../src/reducers.js'); const DbMock = require('../mocks/DbMock'); const db = new DbMock(); const rules = require('../../src/rules'); const dbRequest = require('../../src/storage/dbRequest'); let request = null, store = null, context = null; beforeEach(() => { store = createStore(reducers); context = { db, store, rules }; request = dbRequest.bind(context, [ 'user' ]); expect(store.getState().user).toBeNull(); expect(store.getState().error).toEqual([]); }); it('should get user from database', (done) => { const assert = checkUser.bind(context, [ done ]); store.subscribe(assert); store.dispatch({type: 'NOTE', note: { Id: 1, UserRecordId: 1 }}); request(); }); function checkUser(args) { const state = store.getState(); if(state.user === null) return; const user = state.user; expect(user.Id).toEqual(1); expect(user.Name).toEqual('Jack'); const checkIsCompleted = args[0]; checkIsCompleted(); } }); 

Executo os testes e recebo uma mensagem de que o módulo com as regras não foi encontrado. Mais uma vez, o que o manipulador precisará extrair das regras?


  1. O nome da chave de propriedade do contêiner de propriedade à qual o registro recebido do banco de dados será vinculado
  2. O nome da tabela do banco de dados da qual você deseja extrair o registro
  3. O método que forma a solicitação que precisará ser enviada ao banco de dados para obter uma resposta
  4. O método do dispatcher que envia o registro recebido do banco de dados para o armazenamento de contêiner do estado.
  5. Um método de despacho que envia um erro, se houver, para o armazenamento do contêiner de estado. Decidi primeiro consolidar os erros no contêiner de estado e depois lidar com eles.

O conjunto de regras me parece um dicionário ( Map ), no qual a chave será o nome da propriedade do contêiner de estado e provavelmente formularei o primeiro teste de unidade:


 describe('rules', () => { const rules = require('../src/rules'); it('should contain user rules', () => { const rule = rules.get('user'); expect(rule.table).toEqual('users'); }); }); 

Eu executo os testes e Jasmine me diz que agora tenho dois testes com falha. Para não complicar a tarefa, começarei com uma regra simples que diz que, para atribuir um valor à chave do user do contêiner de status, minha consulta deve ir para dados da tabela de users . Tudo parece ser lógico. Vou escrever como me parece um pequeno código.


 const makeRules = () => { const rules = new Map(); rules.set('user', { table: 'users' }); return rules; }; module.exports = makeRules(); 

Eu executo os testes e vejo que apenas o teste do meu manipulador falha, embora o erro agora seja diferente. No entanto, voltarei a esse teste mais tarde, quando tiver pelo menos uma regra completa no meu dicionário pronta.


Modificarei um pouco o teste do dicionário de regras. Vou adicionar um código que verifica a presença de um método despachante que lida com o erro ao executar uma consulta ao banco de dados:


 describe('rules', () => { const rules = require('../src/rules'); it('should contain user rules', () => { const rule = rules.get('user'); expect(rule.table).toEqual('users'); expect(rule.onError.name).toEqual('dispatchError'); expect(typeof rule.onError).toEqual('function'); }); }); 

Executo os testes, verifique se tenho novamente dois testes com falha e volto a finalizar o código do método de fábrica para gerar o dicionário de regras. Eu adiciono a função ao objeto literal da primeira regra:


 const makeRules = () => { const rules = new Map(); rules.set('user', { table: 'users', onError: function dispatchError(error, store) { const action = { type: 'ERROR', error }; store.dispatch(action); } }); return rules; }; module.exports = makeRules(); 

Executando os testes novamente. O novo fragmento de regra passa no teste com êxito, por isso decido adicionar verificações para todas as regras restantes:


 describe('rules', () => { const rules = require('../src/rules'); it('should contain user rules', () => { const rule = rules.get('user'); expect(rule.table).toEqual('users'); expect(rule.onError.name).toEqual('dispatchError'); expect(typeof rule.onError).toEqual('function'); expect(rule.onSuccess.name).toEqual('dispatchUser'); expect(typeof rule.onSuccess).toEqual('function'); expect(rule.query.name).toEqual('getUserQuery'); expect(typeof rule.query).toEqual('function'); }); }); 

Eu executo testes. O conjunto de testes para o dicionário de regras gera novamente um erro. Estou escrevendo o código:


 const makeRules = () => { const rules = new Map(); rules.set('user', { table: 'users', onError: function dispatchError(error, store) { const action = { type: 'ERROR', error }; store.dispatch(action); }, onSuccess: function dispatchUser(user, store) { const action = { type: 'USER', user }; store.dispatch(action); }, query: function getUserQuery(store) { const state = store.getState(); if(state.note === null) return null; return { Id: state.note.UserRecordId }; } }); return rules; }; module.exports = makeRules(); 

Eu executo testes. O teste do conjunto de regras é novamente executado com êxito e parece-me que agora posso começar a escrever código para a versão realmente nova de solicitação de dados do banco de dados. Desta vez, não usarei a sintaxe da classe, porque não vejo vantagens em seu uso. Haverá muito código de uma vez, porque copio impiedosamente a parte testada da implementação da solicitação existente, complementando-a com uma verificação, caso o registro do banco de dados já tenha sido extraído e colocado no contêiner de status. Então o código:


 function dbRequest(args){ const key = args[0]; const getQuery = this.rules.get(key).query; const dispatchUser = this.rules.get(key).onSuccess; const dispatchError = this.rules.get(key).onError; const tableName = this.rules.get(key).table; const table = this.db.Model.extend({ tableName: tableName }); const state = this.store.getState(); if(state[key] !== null) return; const query = getQuery(this.store); if(query === null) return; table.where(query).fetch().then((item) => { dispatchUser(item, this.store); }).catch((error) => { dispatchError(error, this.store); }); } module.exports = dbRequest; 

Executando testes ... tambor! E eu vejo uma linha de pontos verdes. Todos os testes foram concluídos com sucesso. E, portanto, adicionarei outro teste ao conjunto que verifica a correção do tratamento de erros, embora não tenha esquecido que, para que meu pseudo- DbMock retorne um erro, preciso solicitar a ela uma entrada com um Id igual a 555 :


 it('should add error in store state', (done) => { const assert = checkErrorHasBeenAdded.bind(context, [ done ]); store.subscribe(assert); store.dispatch({type: 'NOTE', note: { Id: 1, UserRecordId: 555 }}); request(); }); function checkErrorHasBeenAdded(args){ const state = store.getState(); if(state.error.length === 0) return; const error = state.error; expect(Array.isArray(error)).toBeTruthy(); expect(error.length).toEqual(1); expect(error[0].message).toEqual('Something goes wrong!'); const checkIsCompleted = args[0]; checkIsCompleted(); } 

Eu executo os testes novamente. Tudo funciona como esperado. Podemos supor que o protótipo correto do comando query no banco de dados esteja pronto e volte a refatorar e desenvolver as regras para a configuração de consultas, porque agora está claro que o código para gerar o conjunto de regras deixará de ser legível após adicionar apenas mais algumas regras no mesmo formato.

Source: https://habr.com/ru/post/pt436654/


All Articles