Design-patterns

Inyección de dependencia

Inyección de dependencia La inyección de dependencia consiste, como su nombre indica, en añadir, insertar dependencia a un objeto. Esto no es recomendable porque creas una dependencia grande entre objetos. Pero en ocasiones es la mejor solución que tenemos para asegurarnos de que el objeto B que usamos dentro del objeto A es el que queremos y como lo queremos, en lugar de uno que importemos. Una interfaz puede ser algo como IDisposable, IEnumerable o IPrintable. Una clase es una implementación real de una o más de estas interfaces: List o Map pueden ser implementaciones de IEnumerable. Para entendernos: a menudo tus clases dependen unas de otras. P.ej. puedes tener una clase database que acceda a su base de datos, pero también deseas que esta clase inicie sesión para acceder a la base de datos. Supongamos que tiene un registrador (logger) entonces la base de datos tiene una dependencia al registrador. Hasta aquí todo bien. Puede modelar esta dependencia dentro de su clase de Base de Datos con la siguiente línea: var logger = new Logger (); y todo está bien Está bien hasta el día en que se da cuenta de que necesita un grupo de registradores: a veces desea iniciar sesión en la consola, a veces en el sistema de archivos, a veces usando TCP / IP y un servidor de registro remoto, y así sucesivamente… Y, por supuesto, NO quieres cambiar todo tu código (mientras tanto, tienes miles de millones) y reemplazar todas las líneas var logger = new Logger (); por: var logger = new TcpLogger (); Primero, esto no es divertido. En segundo lugar, esto es propenso a errores. Tercero, este es un trabajo estúpido y repetitivo para un mono entrenado. Entonces, ¿Qué haces? Obviamente, es una buena idea introducir una interfaz ICanLog (o similar) que implementan todos los registradores. Así que el paso 1 en tu código es lo que haces: ICanLog logger = new Logger (); Ahora que la inferencia de tipo ya no cambia de tipo, siempre tienes una única interfaz contra la cual desarrollar. El siguiente paso es que no desee tener un nuevo Logger() una y otra vez. Así que pones la fiabilidad para crear instancias nuevas en una única clase central de fábrica y obtienes un código como: ICanLog logger = LoggerFactory.Create (); La fábrica misma decide qué tipo de registrador crear. A su código ya no le importa, y si desea cambiar el tipo de registrador que está utilizando, cámbielo una vez: Dentro de la fábrica. De esta manera con la interfaz te aseguras que todas las implementaciones de registrador, sea cual sea actúen de la misma forma ya que implementan la misma interfaz. Esta última último tramo de la publicación es una traducción de una respuesta en StackOverflow la respuesta completa aquí.

Objeto Página (*pageObject*)

Objeto Página (pageObject) Cuando te encuentras haciendo test para una aplicación que no tiene módulos testables y tienes que hacerlo contra la interfaz directamente, es muy probable que te encuentres ante esta situación: // scoreBoard.spec.js // [...] it('should save score after answer a question', function () { startGame(); selectOption(0); submitAnswer(); addPlayerName(players[1]); saveScore(); expectScoreToContainsMinusOne(); }); function startGame() { let startButton = document.getElementById('start-button'); startButton.click(); } function selectOption(optionId) { let answer = document.getElementById(optionId); answer.click(); expect(answer.checked).toBeTruthy(); } // [...] Y luego en otro test lo siguiente: // game.spec.js // [...] it('should start the game, answer a question and change the score', function () { startGame(); selectOption(0); submitAnswer(); expectScoreToBeDifferentFromTheBeginning(); }); function startGame() { let startButton = document.getElementById('start-button'); startButton.click(); } function selectOption(optionId) { let answer = document.getElementById(optionId); answer.click(); expect(answer.checked).toBeTruthy(); } // [...] Estámos repitiendo los mismos métodos startGame() y selectOption() y eso es algo que no nos gusta en el código limpio. Por ello es que existe el PageObject model. Este está formado por funciones que trabajan directamente con la interfaz. De esta manera podemos usar todos las funciones manera unificada con el mismo comportamiento. Extraer al PageObject Creamos nuestro nuevo fichero donde guardar este modulo que hemos decidido extraer y ponemos las funcionalidades que queremos. // pageObject.js export default function pageObject() { function startGame() { let startButton = document.getElementById('start-button'); startButton.click(); } function selectOption(optionId) { let answer = document.getElementById(optionId); answer.click(); expect(answer.checked).toBeTruthy(); } // [...] return { startGame, selectOption }; }; Ahora solo tendremos que importarlo donde lo usábamos anteriormente // game.spec.js import gamePageObject from '../src/pageObject'; // [...] let pageObject = gamepageObject(); it('should start the game, answer a question and change the score', function () { pageObject.startGame(); pageObject.selectOption(0); submitAnswer(); expectScoreToBeDifferentFromTheBeginning(); }); function startGame() { let startButton = document.getElementById('start-button'); startButton.click(); } function selectOption(optionId) { let answer = document.getElementById(optionId); answer.click(); expect(answer.checked).toBeTruthy(); } // [...] De igual forma podemos sacar submitAnswer() si lo vemos necesario. References Martin Fowler post Publicaciones mías sobre Código limpio