Este artículo extiende y trabaja en mayor profundidad los aspectos referentes al mocking que empezamos a ver en el artículo anterior sobre Unit Testing.
El mocking como recordaremos consiste en crear objetos o métodos simulados que representan otro ya existentes en nuestro proyecto. Esto nos abre un gran abanico de posibilidades, desde modificar el comportamiento de un cierto componente o método hasta simular el comportamiento de un método que un compañero nuestro está desarrollando en ese momento pero que necesitamos para poder continuar.
De todas las posibilidades que nos brinda el mocking nos interesa poder evitar que ciertos métodos sean llamados o que la ejecución de los mismos nos devuelva un valor concreto sin tener que preocuparnos por los parámetros de entrada.
En este caso analizaremos diferentes maneras de aplicar las técnicas de mocking para ayudarnos con nuestros unit tests partiendo de la base del framework RaonaData.
El framework RaonaData es un framework
completamente personalizable que
permite el aislamiento total del
código de servidor con el tratamiento
de los datos, siendo compatible además
con la mayoría de bases de datos del
mercado. El framework divide la capa
servidora en dos, por un lado los
Services encargados de la lógica de
negocio y por otro los DataServices
encargados de la interacción con los
datos.
Como ejemplo emplearemos un servicio que guarda una prescripción médica en la base de datos, para ello se emplea una amplia lógica de negocio que deseamos testear y algunas validaciones ajenas al código principal que deseamos obviar.
En primer lugar como no deseamos que la prescripción ficticia que estamos creando sea insertada en la base de datos substituiremos (mockearemos) toda la capa del DataService para simular inserciones correctas. Para ello emplearemos la instrucción “For”:
Con ello substituiremos todo el “DataService” y con la siguiente instrucción definimos un comportamiento por defecto para las inserciones de prescripciones que nos devuelve el entero 1.
Al final de nuestro test (si es el caso) comprobaremos que se ha realizado la llamada al método que insertaría la prescripción:
Por otro lado tenemos la prescripción a guardar. La clase que representa esta entidad contiene el código de validación de sus campos (por ejemplo campos obligatorios) para poder incorporarla al sistema. En este caso no nos interesa que esas validaciones se ejecuten.
Por un lado porque no se encuentra en el objetivo de este test validar ese código (habría que hacerlo en otro diferente) y por otro lado porque aumentaría la complejidad de crear la ficticia instancia de la prescripción.
Para lograr evitar la validación de la entidad pero que la clase mantenga su comportamiento habitual emplearemos el “ForPartsOf” de la siguiente manera:
Es importante fijarnos en la llamada a “DoNotCallBase()”. Ocurre con NSubstitute que en ocasiones cuando instanciamos una entidad empleando “ForPartsOf” y luego queremos substituir el funcionamiento de un método, dicho método es llamado. En este caso si no usamos el “DoNotCallBase()” se realizaría una llamada a “FullValidate” que nos devolvería errores o ejecutaría código que no deseamos ejecutar.
Por último emplearemos el mocking sobre otros servicios que son llamados desde nuestro servicio de guardado y que tampoco nos interesa testear. Estos servicios son substituidos empleando “ForPartsOf” y la sustitución será empleada por el servicio de guardado.
Como hemos visto anteriormente podemos comprobar al final de nuestro test (y usarlo como condición del éxito del test) que dichos métodos son (o no) llamados:
Nota: Received(0) puede ser sustituido
por DidNotReceive()
Como vemos hay varias formas de emplear sustituciones en nuestros test para lograr aislar mejor el código que deseamos testear con nuestras pruebas unitarias y es interesante en especial la capacidad de aislarnos de la base de datos en este caso para agilizar nuestros test y no depender de ella.