Hay dos cuestiones que tenemos que mirar aquí.
La primera es que parece que estás viendo todas tus pruebas desde la perspectiva de la prueba unitaria. Las pruebas unitarias son extremadamente valiosas, pero no son los únicos tipos de pruebas. Las pruebas se pueden dividir en varias capas diferentes, desde pruebas unitarias muy rápidas hasta pruebas de integración menos rápidas e incluso pruebas de aceptación más lentas . (Puede haber incluso más capas rotas, como pruebas funcionales ).
El segundo es que está combinando llamadas a código de terceros con su lógica empresarial, creando desafíos de prueba y posiblemente haciendo que su código sea más frágil.
Las pruebas unitarias deben ser rápidas y deben ejecutarse con frecuencia. Burlarse de las dependencias ayuda a mantener estas pruebas ejecutándose rápidamente, pero potencialmente puede introducir agujeros en la cobertura si la dependencia cambia y el simulacro no lo hace. Su código podría romperse mientras sus pruebas aún se ejecutan en verde. Algunas bibliotecas burlonas lo alertarán si la interfaz de la dependencia cambia, otras no.
Las pruebas de integración, por otro lado, están diseñadas para probar las interacciones entre componentes, incluidas las bibliotecas de terceros. Los simulacros no deben usarse en este nivel de prueba porque queremos ver cómo interactúa el objeto real. Debido a que estamos utilizando objetos reales, estas pruebas serán más lentas y no las ejecutaremos con tanta frecuencia como nuestras pruebas unitarias.
Las pruebas de aceptación miran a un nivel aún más alto, comprobando que se cumplen los requisitos para el software. Estas pruebas se ejecutan contra todo el sistema completo que se implementaría. Una vez más, no se deben usar burlas.
Una pauta que las personas han encontrado valiosa con respecto a los simulacros es no imitar tipos que no son de su propiedad . Amazon posee la API de S3 para que puedan asegurarse de que no cambie debajo de ellos. Usted, por otro lado, no tiene estas garantías. Por lo tanto, si se burla de la API S3 en sus pruebas, podría cambiar y romper su código, mientras que todas sus pruebas se muestran verdes. Entonces, ¿cómo unimos el código de prueba que utiliza bibliotecas de terceros?
Bueno, nosotros no. Si seguimos la directriz, no podemos burlarnos de los objetos que no poseemos. Pero ... si poseemos nuestras dependencias directas, podemos burlarnos de ellas. ¿Pero cómo? Creamos nuestro propio contenedor para la API S3. Podemos hacer que se parezca mucho a la API S3, o podemos hacer que se ajuste más a nuestras necesidades (preferido). Incluso podemos hacerlo un poco más abstracto, digamos un en PersistenceService
lugar de un AmazonS3Bucket
. PersistenceService
sería una interfaz con métodos como #save(Thing)
y #fetch(ThingId)
, los tipos de métodos que nos gustaría ver (estos son ejemplos, en realidad es posible que desee diferentes métodos). Ahora podemos implementar una PersistenceService
API alrededor de S3 (digamos a S3PersistenceService
), encapsulándola lejos de nuestro código de llamada.
Ahora al código que llama a la API S3. Necesitamos reemplazar esas llamadas con llamadas a un PersistenceService
objeto. Usamos la inyección de dependencia para pasar nuestra PersistenceService
al objeto. Es importante no pedir una S3PersistenceService
, sino pedir una PersistenceService
. Esto nos permite intercambiar la implementación durante nuestras pruebas.
Todo el código que solía usar la API S3 directamente ahora usa nuestro PersistenceService
, y nuestro S3PersistenceService
ahora hace todas las llamadas a la API S3. En nuestras pruebas, podemos simularlo PersistenceService
, ya que lo poseemos, y usar el simulacro para asegurarnos de que nuestro código haga las llamadas correctas. Pero ahora eso deja cómo probar S3PersistenceService
. Tiene el mismo problema que antes: no podemos probarlo sin llamar al servicio externo. Entonces ... no lo probamos unitariamente. Nos podríamos burlarse de las dependencias de la API S3, pero esto nos daría poca o ninguna confianza adicional. En cambio, tenemos que probarlo en un nivel superior: pruebas de integración.
Esto puede sonar un poco problemático al decir que no deberíamos hacer una prueba unitaria de una parte de nuestro código, pero veamos lo que logramos. Teníamos un montón de código por todas partes que no pudimos probar unitario que ahora se puede probar unitario a través del PersistenceService
. Tenemos nuestra biblioteca de terceros confinada a una sola clase de implementación. Esa clase debe proporcionar la funcionalidad necesaria para usar la API, pero no tiene ninguna lógica comercial externa asociada. Por lo tanto, una vez que está escrito, debe ser muy estable y no debe cambiar mucho. Podemos confiar en pruebas más lentas que no ejecutamos con tanta frecuencia porque el código es estable.
El siguiente paso es escribir las pruebas de integración para S3PersistenceService
. Deben separarse por nombre o carpeta para que podamos ejecutarlos por separado de nuestras pruebas unitarias rápidas. Las pruebas de integración a menudo pueden usar los mismos marcos de prueba que las pruebas unitarias si el código es suficientemente informativo, por lo que no necesitamos aprender una nueva herramienta. El código real para la prueba de integración es lo que escribiría para su Opción 1.