{"id":12389,"date":"2021-11-02T08:00:35","date_gmt":"2021-11-02T15:00:35","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/?p=12389"},"modified":"2025-06-13T21:03:49","modified_gmt":"2025-06-14T04:03:49","slug":"functional-and-integration-testing-fit-framework","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/es\/functional-and-integration-testing-fit-framework\/","title":{"rendered":"Marco de pruebas funcionales y de integraci\u00f3n (FIT)"},"content":{"rendered":"<p><span style=\"font-weight: 400\">Este blog describe el dise\u00f1o y desarrollo del framework de pruebas, es decir, el framework FIT para transacciones Couchbase en un entorno distribuido. Empezaremos introduci\u00e9ndote en la arquitectura de alto nivel, despu\u00e9s te guiaremos a trav\u00e9s del desarrollo del framework.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Vamos a repasar varios problemas relacionados con las pruebas de los SDK de transacciones y las soluciones a los mismos, y se utilizar\u00e1n ejemplos relevantes mientras se recorre el desarrollo del marco. Aunque en este blog no se mencionan todos los detalles t\u00e9cnicos del marco de trabajo, se intenta dar una visi\u00f3n global del mismo.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Couchbase ofrece transacciones en m\u00faltiples SDKs: Java , Dotnet, y CXX por ahora y con un plan para soportar otros SDKs en un futuro cercano. Probar SDKs que ofrecen la misma funcionalidad plantear\u00eda m\u00faltiples problemas durante la automatizaci\u00f3n de pruebas. La redundancia en la automatizaci\u00f3n de pruebas es el primero que nos vendr\u00eda a la mente a todos. Aparte de la redundancia, tambi\u00e9n tenemos que asegurarnos de que todos los SDKs tienen implementaciones similares de las transacciones de Couchbase. Por ejemplo: el manejo de errores se hace exactamente igual en todos los SDKs. Estos son s\u00f3lo un par de problemas. Con un enfoque principal en Transacciones, este blog proporcionar\u00e1 varios problemas que enfrentar\u00edamos al probar m\u00faltiples SDKs y c\u00f3mo nosotros en Couchbase los hemos resuelto.<\/span><\/p>\n<p><b>Introducci\u00f3n a Couchbase Transactions<\/b><\/p>\n<p><span style=\"font-weight: 400\">Las Transacciones ACID Distribuidas aseguran que cuando m\u00faltiples documentos necesitan ser modificados entonces s\u00f3lo la modificaci\u00f3n exitosa de todos justifica la modificaci\u00f3n de cualquiera, o todas las modificaciones ocurren exitosamente; o ninguna de ellas ocurre. El cumplimiento de Couchbase con las propiedades ACID se puede encontrar <\/span><a href=\"https:\/\/docs.couchbase.com\/server\/current\/learn\/data\/transactions.html\"><span style=\"font-weight: 400\">aqu\u00ed<\/span><\/a><span style=\"font-weight: 400\">.<\/span><\/p>\n<p><b>Transacciones en entornos distribuidos:\u00a0<\/b><\/p>\n<p><b>Cl\u00faster de un solo nodo: <\/b><span style=\"font-weight: 400\">Las transacciones de Couchbase funcionan tanto en clusters multi nodo como en clusters de un solo nodo.  Sin embargo, la configuraci\u00f3n del cl\u00faster debe ser compatible con <\/span><a href=\"https:\/\/docs.couchbase.com\/server\/current\/learn\/data\/durability.html#majority\"><span style=\"font-weight: 400\">Couchbase<\/span><\/a><span style=\"font-weight: 400\">.<\/span><\/p>\n<p><b>Soporte de transacciones para consultas N1QL:<\/b><span style=\"font-weight: 400\"> Aseg\u00farese de que al menos uno de los nodos del cl\u00faster dispone de servicio de consulta<\/span><\/p>\n<p><b>Pruebas del SDK de Couchbase Transactions:<\/b><\/p>\n<p><span style=\"font-weight: 400\">Durante la fase de dise\u00f1o del marco, un an\u00e1lisis en profundidad del plan de pruebas y su automatizaci\u00f3n nos plante\u00f3 m\u00faltiples retos. A continuaci\u00f3n se exponen algunos de los principales retos y sus soluciones. A continuaci\u00f3n, analizaremos el problema y su soluci\u00f3n. Tambi\u00e9n veremos el progreso del desarrollo del marco junto con estas discusiones sobre los problemas.<\/span><\/p>\n<p><b>Problema1: Problema de redundancia:<\/b><\/p>\n<p><span style=\"font-weight: 400\">En Couchbase, actualmente soportamos transacciones en 3 SDK's diferentes: Java , Dotnet, y CXX. En un futuro pr\u00f3ximo soportaremos algunos SDK m\u00e1s, incluyendo Golang. Esto claramente proporciona al QE un problema de redundancia, es decir, podr\u00edamos tener que automatizar el mismo caso de prueba varias veces para cada SDK.\u00a0<\/span><\/p>\n<p><b>Resoluci\u00f3n: <\/b><span style=\"font-weight: 400\">Cada caso de prueba puede clasificarse en 3 partes principales:<\/span><\/p>\n<ol>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Preparaci\u00f3n de pruebas: datos de pruebas, infraestructura de pruebas, etc,\u00a0<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Ejecuci\u00f3n de pruebas, por ejemplo: ejecuci\u00f3n de operaciones de transacci\u00f3n, como insertar, reemplazar, etc. y\u00a0<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Validaci\u00f3n de resultados.<\/span><\/li>\n<\/ol>\n<p><span style=\"font-weight: 400\">Un examen m\u00e1s detallado de estas tres partes revela que las pruebas del SDK s\u00f3lo intervienen en la fase de ejecuci\u00f3n, mientras que la preparaci\u00f3n de las pruebas y la validaci\u00f3n de los resultados son independientes del SDK, es decir, no importa realmente qu\u00e9 SDK se utilice. Esto nos ha llevado a dise\u00f1ar un marco que consta de dos partes: el controlador y el ejecutor. El controlador se encarga de la preparaci\u00f3n completa de la prueba y de la validaci\u00f3n de los resultados. El controlador dirige la ejecuci\u00f3n de la prueba, pero s\u00f3lo de forma abstracta (aprenderemos m\u00e1s sobre esto m\u00e1s adelante), es decir, emite comandos al ejecutor y \u00e9ste los toma y realiza la ejecuci\u00f3n real de la prueba.<\/span><\/p>\n<p><b>Marco FIT <\/b><span style=\"font-weight: 400\">est\u00e1 dise\u00f1ado en un<\/span> <span style=\"font-weight: 400\">modelo cliente-servidor en el que el conductor act\u00faa como cliente y el ejecutor como servidor.<\/span><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-12390 size-full\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2021\/11\/FIT-Framework-Architecture.png\" alt=\"FIT Framework Architecture\" width=\"960\" height=\"540\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/FIT-Framework-Architecture.png 960w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/FIT-Framework-Architecture-300x169.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/FIT-Framework-Architecture-768x432.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/FIT-Framework-Architecture-20x11.png 20w\" sizes=\"auto, (max-width: 960px) 100vw, 960px\" \/><\/p>\n<p><b>Conductor: <\/b><span style=\"font-weight: 400\">Consiste en la preparaci\u00f3n de todas las pruebas y la validaci\u00f3n de los resultados. Todas las pruebas son las pruebas cl\u00e1sicas de Junit y se pueden ejecutar como una sola prueba individual o como un conjunto de pruebas espec\u00edfico o conjunto de pruebas completo . Todas las pruebas se escriben una sola vez. Estas pruebas se pueden reutilizar para todos los SDK.<\/span><\/p>\n<p><b>Int\u00e9rprete:<\/b><span style=\"font-weight: 400\"> Se trata de una sencilla aplicaci\u00f3n escrita una vez para cada SDK. Dentro de un controlador, cada prueba se moldea en forma de objeto Java y se env\u00eda al <\/span><a href=\"https:\/\/grpc.io\/\"><span style=\"font-weight: 400\">gRPC<\/span><\/a><span style=\"font-weight: 400\"> Capa. El protocolo gRPC convierte este objeto Java en un objeto de prueba espec\u00edfico del lenguaje y lo env\u00eda al ejecutor. El ejecutor obtiene este objeto de prueba, lee las instrucciones y ejecuta las operaciones de transacci\u00f3n necesarias. Una vez completada la transacci\u00f3n, el ejecutor recupera el resultado y lo env\u00eda de vuelta al controlador a trav\u00e9s del protocolo gRPC.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Una vez que el controlador recibe el objeto de resultado, procede a la validaci\u00f3n del resultado.<\/span><b>Proceso de desarrollo de pruebas:<\/b><span style=\"font-weight: 400\"> Ahora que ya tenemos una idea general de c\u00f3mo funcionan el controlador y el ejecutor dentro del marco FIT, veamos el aspecto t\u00e9cnico y c\u00f3mo interact\u00faan entre s\u00ed mediante unas sencillas pruebas de ejemplo.<\/span><\/p>\n<p><b>Ej1: Probar transacciones con una sola operaci\u00f3n: Operaci\u00f3n \"reemplazar\" b\u00e1sica\u00a0<\/b><\/p>\n<p><b>C\u00f3digo del conductor:\u00a0<\/b><\/p>\n<table>\n<tbody>\n<tr>\n<td>\n<pre class=\"\"> \u00a0 @Test\r\n \u00a0\u00a0public void oneUpdateCommitted() {\r\n \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0collection.upsert(docId, initial); \u00a0 \/\/ Test Preparation\r\n \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0TransactionResult result = TransactionBuilder.create(shared)\r\n \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.replace(docId, updated)\r\n \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.sendToPerformer();\u00a0 \u00a0 \u00a0 \/\/ Test Execution\r\n \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/\/Result validation\r\n \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0assertCompletedInSingleAttempt(shared, collection, result);\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\r\n \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0assertDocExistsAndNotInTransactionAndContentEquals(collection, docId, updated);\r\n \u00a0\u00a0}<\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><span style=\"font-weight: 400\">Como se puede ver todas las pruebas se escriben siempre una sola vez y como pruebas Junit.<\/span><\/p>\n<p><span style=\"font-weight: 400\">La preparaci\u00f3n de la prueba y la validaci\u00f3n de los resultados son independientes del SDK, por lo que se realizan en la propia prueba Junit.\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400\">Sin embargo, la parte de ejecuci\u00f3n de la prueba se hace de forma abstracta. En la parte superior, parecer\u00e1 que se ejecuta en el propio controlador. Pero se involucra en la computaci\u00f3n distribuida siguiendo la llamada a procedimiento remoto. Toda la prueba se convierte en un objeto Java, denominado objeto \"TransactionBuilder\" en nuestro marco FIT, utilizando la clase Transaction Builder y, a continuaci\u00f3n, se env\u00eda al ejecutor a trav\u00e9s de la capa gRPC utilizando el m\u00e9todo \"sendToPerfomer\".\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400\">En este ejemplo en el que intentamos probar la operaci\u00f3n de reemplazo de transacciones, creamos un objeto Java que contendr\u00e1 todos los detalles:<\/span><\/p>\n<ol>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Id del documento en el que se supone que se ejecuta la transacci\u00f3n\u00a0<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Valor actualizado, es decir, el nuevo valor que queremos que la transacci\u00f3n imponga al documento.<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Operaci\u00f3n de transacci\u00f3n, en este caso es \"reemplazar\"<\/span><\/li>\n<\/ol>\n<p><span style=\"font-weight: 400\">Una vez creado dicho objeto java , el sendToPerformer simplemente invoca la funci\u00f3n <\/span><a href=\"https:\/\/grpc.io\/\"><span style=\"font-weight: 400\">gRPC<\/span><\/a><span style=\"font-weight: 400\"> para enviarla al servidor.<\/span><\/p>\n<p><b>Consulte el c\u00f3digo Java Performer : <\/b><a href=\"https:\/\/github.com\/couchbaselabs\/blog-fit-performer\/blob\/main\/basicPerformer.java\"><b>basicPerformer<\/b><\/a><\/p>\n<p><span style=\"font-weight: 400\">As\u00ed que en el primer paso, el ejecutor lee el objeto de prueba y comprueba la operaci\u00f3n que necesita ejecutar. En nuestro ejemplo, como se trata de una operaci\u00f3n de reemplazo, op.hasReplace() devolver\u00e1 true y op.hasInsert(), op.hasRemove() etc devolver\u00e1n false.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Dentro del bloque de c\u00f3digo replace, el ejecutor recupera el id del documento, la ubicaci\u00f3n del documento y el valor actualizado del documento. Una vez recuperada toda la informaci\u00f3n relevante, el ejecutor ejecuta la transacci\u00f3n, es decir, la operaci\u00f3n ctx.replace().<\/span><\/p>\n<p><span style=\"font-weight: 400\">Una vez que la transacci\u00f3n se ha ejecutado correctamente, el resultado se env\u00eda de vuelta al controlador y \u00e9ste, de forma similar, recupera la informaci\u00f3n relevante del objeto de resultado y realiza la validaci\u00f3n del resultado.<\/span><\/p>\n<p><b>Ejemplos de funcionalidades probadas: <\/b><span style=\"font-weight: 400\">Esta caracter\u00edstica del marco nos ayud\u00f3 a probar el SDK de transacciones no s\u00f3lo para el contenido del documento, sino tambi\u00e9n para los metadatos de la transacci\u00f3n, es decir, los metadatos esperados est\u00e1n presentes siempre que sea necesario y los metadatos se eliminan siempre que sea necesario.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Ahora que ya tenemos algunas nociones t\u00e9cnicas sobre el marco FIT, entremos un poco m\u00e1s en detalle:<\/span><\/p>\n<p><b>Eg2: Comprobaci\u00f3n de transacciones con m\u00e1s de una operaci\u00f3n:<\/b><\/p>\n<p><b>C\u00f3digo del conductor:<\/b><\/p>\n<table>\n<tbody>\n<tr>\n<td>\n<pre class=\"\"> \u00a0 @Test\r\n \u00a0\u00a0\u00a0void insertReplaceTest() {\r\n \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0collection.upsert(docId2, initial); \/\/Test preparation\r\n \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0TransactionResult result = TransactionBuilder.create(shared)\r\n \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.insert(docId1, initial)\r\n \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.replace(docId2, updated)\r\n \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.sendToPerformer();\u00a0 \/\/Actual Test Execution\r\n \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/\/Result validation\r\n \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0assertCompletedInSingleAttempt(shared, collection, result);\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\r\n \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0assertDocExistsAndNotInTransactionAndContentEquals(collection, docId1, initial);\r\n \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0assertDocExistsAndNotInTransactionAndContentEquals(collection, docId2, updated);\r\n \u00a0\u00a0\u00a0}<\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><span style=\"font-weight: 400\">En esta prueba, la transacci\u00f3n realiza la inserci\u00f3n del documento con docId1 y la sustituci\u00f3n del documento con docId2. As\u00ed que tenemos que a\u00f1adir \"insertar\" y \"reemplazar\" en el objeto de prueba y toda la informaci\u00f3n necesaria para cada una de estas operaciones se env\u00eda al ejecutor.<\/span><\/p>\n<p><b>Consulte el c\u00f3digo Java Performer : <\/b><a href=\"https:\/\/github.com\/couchbaselabs\/blog-fit-performer\/blob\/main\/performerSupportsTwoOps.java\"><b>performerSupportsTwoOps<\/b><\/a><\/p>\n<p><span style=\"font-weight: 400\">Dado que tenemos insertar y reemplazar , el op.Insert devolver\u00e1 true y el ejecutor recupera la informaci\u00f3n requerida y realiza la inserci\u00f3n y luego op.replace() devolver\u00e1 true y luego el ejecutor ejecuta las operaciones de reemplazo y devuelve el resultado al controlador.<\/span><\/p>\n<p><b>Ejemplos de funcionalidades probadas:<\/b><span style=\"font-weight: 400\"> Inicialmente no soport\u00e1bamos todas las operaciones v\u00e1lidas de transacciones m\u00faltiples sobre el mismo documento en la misma transacci\u00f3n.Cuando se a\u00f1adieron, pudimos probar esa funcionalidad con este comportamiento del framework. Tambi\u00e9n se probaron las operaciones m\u00faltiples regulares de transacciones en diferentes documentos. Problemas como transacciones que fallan al reemplazar\/eliminar documentos y caducidad fueron probados bien con este soporte.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Hemos visto en ambos ejemplos que se espera que la transacci\u00f3n tenga \u00e9xito. Sin embargo, para los escenarios de casos negativos, esperamos que la transacci\u00f3n arroje errores\/excepciones. Estos errores\/excepciones son espec\u00edficos del SDK por lo que necesitan ser manejados en el ejecutor. As\u00ed que el controlador necesita decirle al ejecutor qu\u00e9 error\/excepci\u00f3n debe exceptuar y el ejecutor necesita hacer esta validaci\u00f3n.<\/span><\/p>\n<p><b>Problem2 Verificaci\u00f3n de errores:<\/b><\/p>\n<ol>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Para diferentes causas, la transacci\u00f3n debe entender la causa y lanzar el error\/excepci\u00f3n correspondiente. As\u00ed que no s\u00f3lo ten\u00edamos que probar la funcionalidad de las transacciones, sino tambi\u00e9n los c\u00f3digos de error y las excepciones lanzadas por ellas.<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">La gesti\u00f3n de excepciones de transacci\u00f3n es diferente para cada error\/excepci\u00f3n: La excepci\u00f3n de documento no encontrado debe tratarse de forma diferente a algunas excepciones transitorias.\u00a0<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Incluso para la misma excepci\u00f3n, la fase de la transacci\u00f3n en la que se produce tambi\u00e9n da lugar a un tratamiento diferente. Por ejemplo: los conflictos de escritura para insertar\/reemplazar se tratan de forma diferente que para las operaciones de obtenci\u00f3n.<\/span><\/li>\n<\/ol>\n<p><b>Resoluci\u00f3n: <\/b><span style=\"font-weight: 400\">El controlador debe enviar los c\u00f3digos de las causas y excepciones al ejecutor. El ejecutor leer\u00e1 los c\u00f3digos para las causas de fallo y las inducir\u00e1 utilizando Hooks.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Los hooks son implementaciones internas de Couchbase que ayudan a probar escenarios de fallo. En nuestro ejemplo de abajo s\u00f3lo estamos tratando de crear un vencimiento antes de insertar un documento<\/span><\/p>\n<p><span style=\"font-weight: 400\">Una vez inducido el fallo, el ejecutor tambi\u00e9n esperar\u00e1 el error\/excepci\u00f3n que se supone que esta transacci\u00f3n debe lanzar. Si no se lanza la excepci\u00f3n o se lanza una expectativa incorrecta, el ejecutor falla las pruebas y env\u00eda el fallo en el objeto de resultado al controlador. El controlador lee este objeto de resultado y proporciona el fallo esperado y el real como salida.<\/span><\/p>\n<p><b>Eg3: Probar escenarios de casos negativos :<\/b><\/p>\n<p><b>C\u00f3digo del conductor:<\/b><\/p>\n<table>\n<tbody>\n<tr>\n<td>\n<pre class=\"\">@Test\r\n \u00a0\u00a0\u00a0void expiryDuringFirstOpInTransactionEntersExpiryOvertime() {\r\n \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0String docId = TestUtils.docId(collection, 0);\r\n \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0TransactionResult result = TransactionBuilder.create(shared)\r\n \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.injectExpiryAtPoint(StagePoints.HOOK_INSERT)\r\n \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.insert(docId, updated, EXPECT_FAIL_EXPIRY)\r\n \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.sendToPerformer();\r\n \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0ResultValidator.assertNotStarted(collection, result);\r\n \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0DocValidator.assertDocDoesNotExist(collection, docId);\r\n \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0assertEquals(TransactionException.EXCEPTION_EXPIRED, result.getException());\r\n \u00a0\u00a0\u00a0}<\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><span style=\"font-weight: 400\">As\u00ed que en esta prueba, el controlador le est\u00e1 diciendo al ejecutor que ejecute la inserci\u00f3n y que espere que la transacci\u00f3n expire durante esta operaci\u00f3n de inserci\u00f3n. Enviamos el c\u00f3digo \"EXPECT_FAIL_EXPIRY\" para transmitir esto al ejecutor.<\/span><\/p>\n<p><b>Consulte el c\u00f3digo Java Performer : <\/b><a href=\"https:\/\/github.com\/couchbaselabs\/blog-fit-performer\/blob\/main\/performerSupportsErrorHandling.java\"><b>performerSupportsErrorHandling<\/b><\/a><\/p>\n<p><b>Ejemplos de funcionalidades probadas: <\/b><span style=\"font-weight: 400\">Se comprobaron todos los c\u00f3digos de error y gesti\u00f3n de errores\/excepciones. Se realizaron pruebas funcionales relacionadas con cualquier SDK no compatible o no sincronizado con la funcionalidad acordada de gesti\u00f3n de errores. La funci\u00f3n de caducidad de transacciones se prob\u00f3 correctamente con este soporte del marco.\u00a0\u00a0<\/span><\/p>\n<p><b>Problema 3: Gesti\u00f3n de versiones:<\/b><span style=\"font-weight: 400\"> Tenemos que probar diferentes versiones de la biblioteca de transacciones y las versiones posteriores tendr\u00edan nuevas caracter\u00edsticas que no est\u00e1n disponibles en el anterior<\/span> <span style=\"font-weight: 400\">versi\u00f3n. As\u00ed que el marco de pruebas tuvo que entender qu\u00e9 caracter\u00edstica no es compatible y evitar la ejecuci\u00f3n de esas pruebas.\u00a0<\/span><\/p>\n<p><b>Resoluci\u00f3n: <\/b><span style=\"font-weight: 400\">Hemos utilizado las extensiones de ejecuci\u00f3n de pruebas de condiciones de Junit5. Cada testsuite est\u00e1 anotado con una condici\u00f3n \"@IgnoreWhen\". Todas las condiciones mencionadas en ella ser\u00e1n recuperadas y utilizadas en el m\u00e9todo \"ExecuteWhen\" que anulamos. Antes de que el controlador comience a ejecutar cualquier prueba, se pondr\u00e1 en contacto con el ejecutor y obtendr\u00e1 todas las funcionalidades soportadas por \u00e9l. El m\u00e9todo \"ExecuteWhen\" utilizar\u00e1 la informaci\u00f3n proporcionada en \"@IgnoreWhen\" y las capacidades del ejecutor y decidir\u00e1 si un conjunto de pruebas debe ser ejecutado o ignorado.\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400\">Eg3:<\/span><\/p>\n<p><b>Consulte el c\u00f3digo del controlador Java : <\/b><a href=\"https:\/\/github.com\/couchbaselabs\/blog-fit-performer\/blob\/main\/driverSupportsVersionManagement.java\"><b>driverSupportsVersionManagement<\/b><\/a><\/p>\n<p><b>Ejemplos de funcionalidades probadas: <\/b><span style=\"font-weight: 400\">El SDK que desarroll\u00f3 una caracter\u00edstica un poco m\u00e1s tarde que otros SDK, podr\u00eda utilizar esta caracter\u00edstica de la FIT para activar estas pruebas una vez que implementaron su caracter\u00edstica. Esto nos ayud\u00f3 en el desarrollo dirigido por pruebas.<\/span><\/p>\n<p><b>Problema 4: M\u00faltiples int\u00e9rpretes: <\/b><span style=\"font-weight: 400\">\u00a0<\/span><b>Transacciones paralelas:<\/b><\/p>\n<p><span style=\"font-weight: 400\">Las transacciones pueden ejecutarse en paralelo. Las transacciones de Couchbase confirman el modelo de aislamiento.   Es decir, cuando dos o m\u00e1s transacciones se ejecutan en el mismo conjunto de documentos no deber\u00edan conducir a escrituras\/lecturas sucias. Para probar esto, si ejecutamos aleatoriamente 'n' transacciones en paralelo y en caso de que cause corrupci\u00f3n de documentos, ser\u00eda dif\u00edcil saber qu\u00e9 caus\u00f3 exactamente la corrupci\u00f3n. Cada transacci\u00f3n puede tener muchas operaciones y cada operaci\u00f3n tendr\u00eda m\u00faltiples etapas. En qu\u00e9 operaci\u00f3n y en qu\u00e9 etapa colisionaron estas transacciones es algo que necesitamos saber si necesitamos resolver el problema.<\/span><\/p>\n<p><b>Resoluci\u00f3n: <\/b><span style=\"font-weight: 400\">Hemos dise\u00f1ado un mecanismo de enclavamiento en el que una transacci\u00f3n ejecuta unas cuantas operaciones o unas cuantas etapas de una operaci\u00f3n e indica a la otra transacci\u00f3n que se ponga en marcha. Esta primera transacci\u00f3n espera ahora a que la segunda se ejecute y alcance una etapa deseada. Una vez que la segunda transacci\u00f3n alcanza una etapa determinada, notifica a la primera transacci\u00f3n que contin\u00fae. Esto es efectivamente lo que ocurre incluso para las transacciones paralelas. As\u00ed que se nos ocurri\u00f3 un conjunto de puntos de colisi\u00f3n que podr\u00edan dar lugar a conflictos de escritura-escritura o lecturas sucias y utilizamos los latches para automatizar estos casos de prueba.<\/span><\/p>\n<p><b>Consulte el c\u00f3digo del controlador Java : <\/b><a href=\"https:\/\/github.com\/couchbaselabs\/blog-fit-performer\/blob\/main\/driverParallelTransactions.java\"><b>driverParallelTransactions<\/b><\/a><\/p>\n<p><b>C\u00f3digo del conductor:<\/b><\/p>\n<p><b>Ejemplos de funcionalidad probada\/errores encontrados: <\/b><span style=\"font-weight: 400\">Las transacciones concurrentes se probaron con este soporte<\/span><\/p>\n<p><b>Problema5: M\u00faltiples ejecutores:  Transacciones paralelas para diferentes SDK:<\/b><\/p>\n<p><span style=\"font-weight: 400\">Dado que soportamos transacciones en m\u00faltiples SDK's, la misma l\u00f3gica puede ser usada mientras se prueba la ejecuci\u00f3n paralela de transacciones con diferentes SDK's. Por ejemplo: transacciones Java frente a transacciones CXX. En el ejemplo anterior, nos conectamos al mismo Performer ya que quer\u00edamos ejecutar transacciones paralelas para el mismo SDK. En este caso, TXN A se conectar\u00e1 al Performer A (supongamos que el Performer A est\u00e1 usando Transacciones Java) y Txn B se conectar\u00e1 al Performer B (ejecutando transacciones CXX)<\/span><\/p>\n<p><b>Consulte el c\u00f3digo del controlador Java : <\/b><a href=\"https:\/\/github.com\/couchbaselabs\/blog-fit-performer\/blob\/main\/driverMultiplePerformers.java\"><b>driverMultiplePerformers<\/b><\/a><\/p>\n<p><b>Ejemplos de funcionalidad probada\/errores encontrados: <\/b><span style=\"font-weight: 400\">Las transacciones concurrentes con diferentes clientes SDK se probaron con este soporte. Tambi\u00e9n nos ayud\u00f3 a garantizar que los metadatos de la transacci\u00f3n estuvieran intactos.<\/span><\/p>\n<p><b>Conclusi\u00f3n:<\/b><\/p>\n<p><span style=\"font-weight: 400\">Este dise\u00f1o arquitect\u00f3nico del marco FIT no s\u00f3lo nos ayud\u00f3 a resolver los problemas que se nos plantearon, sino que tambi\u00e9n nos ayud\u00f3 en la automatizaci\u00f3n de pruebas eficiente y ayud\u00f3 al desarrollo de transacciones en el modo de desarrollo dirigido por pruebas (TDD).\u00a0<\/span><\/p>\n<p><b>Automatizaci\u00f3n eficaz de las pruebas<\/b><span style=\"font-weight: 400\">: Dividir el marco en un \u00fanico controlador y varios ejecutores nos ayud\u00f3 a desarrollar partes del marco de forma independiente. El desarrollador de cada SDK nos proporcion\u00f3 el int\u00e9rprete y el QE pudo centrarse en la automatizaci\u00f3n de las pruebas, es decir, en el controlador. Los desarrolladores tambi\u00e9n pod\u00edan a\u00f1adir pruebas unitarias al controlador para que todas las pruebas de las transacciones fueran gestionadas por este \u00fanico marco.<\/span><\/p>\n<p><b>Desarrollo basado en pruebas (TDD)<\/b><span style=\"font-weight: 400\">: Hemos desarrollado el int\u00e9rprete java y escrito todas las pruebas necesarias para firmar las primeras versiones de las transacciones para Java SDK. Una vez que Java SDK fue liberado y el desarrollo de otras transacciones SDK es decir, CXX y dot net comenz\u00f3, nuestro equipo de desarrollo tuvo que desarrollar la aplicaci\u00f3n int\u00e9rprete, mientras que la reutilizaci\u00f3n de la misma aplicaci\u00f3n controlador. Esto les ayud\u00f3 a desarrollar su SDK de forma TDD.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Esperamos que haya disfrutado de este blog. Estamos a\u00f1adiendo m\u00e1s funciones a este marco y publicaremos un nuevo blog en el que describiremos los nuevos problemas y las nuevas soluciones. Mientras tanto, si desea m\u00e1s informaci\u00f3n sobre el marco FIT, p\u00f3ngase en contacto con <\/span><a href=\"mailto:praneeth.bokka@couchbase.com\"><span style=\"font-weight: 400\">praneeth.bokka@couchbase.com<\/span><\/a><span style=\"font-weight: 400\">. Para obtener m\u00e1s informaci\u00f3n sobre las transacciones de Couchbase, visite <\/span><a href=\"https:\/\/docs.couchbase.com\/server\/current\/learn\/data\/transactions.html\"><span style=\"font-weight: 400\">Transacciones Couchbase<\/span><\/a><\/p>","protected":false},"excerpt":{"rendered":"<p>This blog describes the design and development of the test framework i.e FIT framework for Couchbase transactions in a distributed environment. We&#8217;ll start out by introducing you to high-level architectural insight, then we&#8217;ll walk you through the development of the [&hellip;]<\/p>","protected":false},"author":79214,"featured_media":12394,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[1811,1821,1818,2201],"tags":[],"ppma_author":[9481],"class_list":["post-12389","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dotnet","category-couchbase-architecture","category-java","category-tools-sdks"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.9 (Yoast SEO v25.9) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Functional + Integration Testing (FIT) Framework + Design<\/title>\n<meta name=\"description\" content=\"This Couchbase post describes the design and development of the test framework like FIT framework for transactions in a distributed environment.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.couchbase.com\/blog\/es\/functional-and-integration-testing-fit-framework\/\" \/>\n<meta property=\"og:locale\" content=\"es_MX\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Functional and Integration testing (FIT) Framework\" \/>\n<meta property=\"og:description\" content=\"This Couchbase post describes the design and development of the test framework like FIT framework for transactions in a distributed environment.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/es\/functional-and-integration-testing-fit-framework\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:published_time\" content=\"2021-11-02T15:00:35+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-06-14T04:03:49+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/christina-wocintechchat-com-FVgECvTjlBQ-unsplash-scaled.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"2560\" \/>\n\t<meta property=\"og:image:height\" content=\"1709\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Praneeth Bokka\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Praneeth Bokka\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"11 minutos\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/functional-and-integration-testing-fit-framework\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/functional-and-integration-testing-fit-framework\/\"},\"author\":{\"name\":\"Praneeth Bokka\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/beab3b1ad6897af1bd7d09aca683201b\"},\"headline\":\"Functional and Integration testing (FIT) Framework\",\"datePublished\":\"2021-11-02T15:00:35+00:00\",\"dateModified\":\"2025-06-14T04:03:49+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/functional-and-integration-testing-fit-framework\/\"},\"wordCount\":2464,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/functional-and-integration-testing-fit-framework\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/christina-wocintechchat-com-FVgECvTjlBQ-unsplash-scaled.jpg\",\"articleSection\":[\".NET\",\"Couchbase Architecture\",\"Java\",\"Tools &amp; SDKs\"],\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/functional-and-integration-testing-fit-framework\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/functional-and-integration-testing-fit-framework\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/functional-and-integration-testing-fit-framework\/\",\"name\":\"Functional + Integration Testing (FIT) Framework + Design\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/functional-and-integration-testing-fit-framework\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/functional-and-integration-testing-fit-framework\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/christina-wocintechchat-com-FVgECvTjlBQ-unsplash-scaled.jpg\",\"datePublished\":\"2021-11-02T15:00:35+00:00\",\"dateModified\":\"2025-06-14T04:03:49+00:00\",\"description\":\"This Couchbase post describes the design and development of the test framework like FIT framework for transactions in a distributed environment.\",\"breadcrumb\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/functional-and-integration-testing-fit-framework\/#breadcrumb\"},\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/functional-and-integration-testing-fit-framework\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/functional-and-integration-testing-fit-framework\/#primaryimage\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/christina-wocintechchat-com-FVgECvTjlBQ-unsplash-scaled.jpg\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/christina-wocintechchat-com-FVgECvTjlBQ-unsplash-scaled.jpg\",\"width\":2560,\"height\":1709},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/functional-and-integration-testing-fit-framework\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.couchbase.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Functional and Integration testing (FIT) Framework\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"name\":\"The Couchbase Blog\",\"description\":\"Couchbase, the NoSQL Database\",\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"es\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\",\"name\":\"The Couchbase Blog\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"width\":218,\"height\":34,\"caption\":\"The Couchbase Blog\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/beab3b1ad6897af1bd7d09aca683201b\",\"name\":\"Praneeth Bokka\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/0b23c9b410f0b7e0c2477863774d6225\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/Screen-Shot-2021-11-01-at-3.32.08-PM.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/Screen-Shot-2021-11-01-at-3.32.08-PM.png\",\"caption\":\"Praneeth Bokka\"},\"url\":\"https:\/\/www.couchbase.com\/blog\/es\/author\/praneeth-bokka\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Functional + Integration Testing (FIT) Framework + Design","description":"Este post de Couchbase describe el dise\u00f1o y desarrollo del marco de pruebas como marco FIT para transacciones en un entorno distribuido.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.couchbase.com\/blog\/es\/functional-and-integration-testing-fit-framework\/","og_locale":"es_MX","og_type":"article","og_title":"Functional and Integration testing (FIT) Framework","og_description":"This Couchbase post describes the design and development of the test framework like FIT framework for transactions in a distributed environment.","og_url":"https:\/\/www.couchbase.com\/blog\/es\/functional-and-integration-testing-fit-framework\/","og_site_name":"The Couchbase Blog","article_published_time":"2021-11-02T15:00:35+00:00","article_modified_time":"2025-06-14T04:03:49+00:00","og_image":[{"width":2560,"height":1709,"url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/christina-wocintechchat-com-FVgECvTjlBQ-unsplash-scaled.jpg","type":"image\/jpeg"}],"author":"Praneeth Bokka","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Praneeth Bokka","Est. reading time":"11 minutos"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.couchbase.com\/blog\/functional-and-integration-testing-fit-framework\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/functional-and-integration-testing-fit-framework\/"},"author":{"name":"Praneeth Bokka","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/beab3b1ad6897af1bd7d09aca683201b"},"headline":"Functional and Integration testing (FIT) Framework","datePublished":"2021-11-02T15:00:35+00:00","dateModified":"2025-06-14T04:03:49+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/functional-and-integration-testing-fit-framework\/"},"wordCount":2464,"commentCount":0,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/functional-and-integration-testing-fit-framework\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/christina-wocintechchat-com-FVgECvTjlBQ-unsplash-scaled.jpg","articleSection":[".NET","Couchbase Architecture","Java","Tools &amp; SDKs"],"inLanguage":"es","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/functional-and-integration-testing-fit-framework\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/functional-and-integration-testing-fit-framework\/","url":"https:\/\/www.couchbase.com\/blog\/functional-and-integration-testing-fit-framework\/","name":"Functional + Integration Testing (FIT) Framework + Design","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/functional-and-integration-testing-fit-framework\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/functional-and-integration-testing-fit-framework\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/christina-wocintechchat-com-FVgECvTjlBQ-unsplash-scaled.jpg","datePublished":"2021-11-02T15:00:35+00:00","dateModified":"2025-06-14T04:03:49+00:00","description":"Este post de Couchbase describe el dise\u00f1o y desarrollo del marco de pruebas como marco FIT para transacciones en un entorno distribuido.","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/functional-and-integration-testing-fit-framework\/#breadcrumb"},"inLanguage":"es","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/functional-and-integration-testing-fit-framework\/"]}]},{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/www.couchbase.com\/blog\/functional-and-integration-testing-fit-framework\/#primaryimage","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/christina-wocintechchat-com-FVgECvTjlBQ-unsplash-scaled.jpg","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/christina-wocintechchat-com-FVgECvTjlBQ-unsplash-scaled.jpg","width":2560,"height":1709},{"@type":"BreadcrumbList","@id":"https:\/\/www.couchbase.com\/blog\/functional-and-integration-testing-fit-framework\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Functional and Integration testing (FIT) Framework"}]},{"@type":"WebSite","@id":"https:\/\/www.couchbase.com\/blog\/#website","url":"https:\/\/www.couchbase.com\/blog\/","name":"El blog de Couchbase","description":"Couchbase, la base de datos NoSQL","publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"es"},{"@type":"Organization","@id":"https:\/\/www.couchbase.com\/blog\/#organization","name":"El blog de Couchbase","url":"https:\/\/www.couchbase.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","width":218,"height":34,"caption":"The Couchbase Blog"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/beab3b1ad6897af1bd7d09aca683201b","name":"Praneeth Bokka","image":{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/0b23c9b410f0b7e0c2477863774d6225","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/Screen-Shot-2021-11-01-at-3.32.08-PM.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/Screen-Shot-2021-11-01-at-3.32.08-PM.png","caption":"Praneeth Bokka"},"url":"https:\/\/www.couchbase.com\/blog\/es\/author\/praneeth-bokka\/"}]}},"authors":[{"term_id":9481,"user_id":79214,"is_guest":0,"slug":"praneeth-bokka","display_name":"Praneeth Bokka","avatar_url":{"url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/Screen-Shot-2021-11-01-at-3.32.08-PM.png","url2x":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/Screen-Shot-2021-11-01-at-3.32.08-PM.png"},"author_category":"","last_name":"Bokka","first_name":"Praneeth","job_title":"","user_url":"","description":""}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/posts\/12389","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/users\/79214"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/comments?post=12389"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/posts\/12389\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/media\/12394"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/media?parent=12389"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/categories?post=12389"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/tags?post=12389"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/ppma_author?post=12389"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}