Biblioteca para retirar y establecer expectativas en las solicitudes HTTP en Delphi con Dunitx.
* WebMocks se desarrolló en Delphi 10.3 (Río) y 10.4 (Sydney) y hasta que la versión 3.0 fue compatible de regreso a XE8. A medida que WebMocks utiliza la biblioteca System.Net introducida con XE8, no será compatible con versiones anteriores. Si necesita instalar en versiones de Delphi antes de 10.3, debe instalar la versión 2.0.0.
WebMocks 3.2.0 está disponible a través del Administrador de paquetes de Embarcadero para Delphi Getit. Si tiene una versión reciente de Delphi, incluido Getit, este debería ser el método de instalación preferido.
WebMocks ahora debe aparecer en Delphinus Package Manager.
Asegúrese de reiniciar Delphi después de instalar a través de Delphinus, de lo contrario, las unidades no se pueden encontrar en sus proyectos de prueba.
Source extraído a la "ruta de la biblioteca" y "ruta de navegación". Si desea una introducción suave a WebMocks para Delphi, hay una serie de artículos publicados en Dev que comienzan con la prueba de clientes HTTP en Delphi con Dunitx y WebMocks.
Delphi-Webmocks-Demos contiene un conjunto de manifestaciones para acompañar los artículos.
La versión 2 ha dejado caer el Delphi. espacio de nombres de todas las unidades. Cualquier proyecto actualizado a la versión 2 o posterior deberá soltar el Delphi. Prefijo de cualquier unidades de WebMocks incluidas.
En su archivo de unidad de prueba se requieren un par de pasos simples.
WebMock a sus uses interfaz.TestFixture , use Setup y TearDown para crear/destruir una instancia de TWebMock . unit MyTestObjectTests;
interface
uses
DUnitX.TestFramework,
MyObjectUnit,
WebMock;
type
TMyObjectTests = class (TObject)
private
WebMock: TWebMock;
Subject: TMyObject;
public
[Setup]
procedure Setup ;
[TearDown]
procedure TearDown ;
[Test]
procedure TestGet ;
end ;
implementation
procedure TMyObjectTests.Setup ;
begin
WebMock := TWebMock.Create;
end ;
procedure TMyObjectTests.TearDown ;
begin
WebMock.Free;
end ;
procedure TMyObjectTests.TestGet ;
begin
// Arrange
// Stub the request
WebMock.StubRequest( ' GET ' , ' /endpoint ' );
// Create your subject and point it at the endpoint
Subject := TMyObject.Create;
Subject.EndpointURL := WebMock.URLFor( ' endpoint ' );
// Act
Subject.Get;
// Assert: check your subject behaved correctly
Assert.IsTrue(Subject.ReceivedResponse);
end ;
initialization
TDUnitX.RegisterTestFixture(TMyObjectTests);
end . Por defecto, TWebMock se unirá a un puerto asignado dinámicamente el inicio en 8080 . Este comportamiento se puede anular especificando un puerto en la creación.
WebMock := TWebMock.Create( 8088 ); El uso de WebMock.URLFor Función dentro de sus pruebas es simplificar la construcción de una URL válida. La propiedad Port contiene el puerto limitado actual y la propiedad BaseURL contiene una URL válida para la raíz del servidor.
La forma más simple de coincidencia de solicitud y punto de partida para todos los trozos de solicitud es mediante el método HTTP y la ruta del documento. Por ejemplo, el revestimiento del verbo HTTP GET la raíz del servidor / se logra por:
WebMock.StubRequest( ' GET ' , ' / ' ); El uso de un solo carácter de tarjeta salvaje * se puede usar para que coincida con cualquier solicitud. Por ejemplo, para que coincida con todas las solicitudes POST , independientemente de la ruta del documento que pueda usar:
WebMock.StubRequest( ' POST ' , ' * ' );Del mismo modo, para que coincida con cualquier método HTTP para una ruta dada que pueda usar:
WebMock.StubRequest( ' * ' , ' /path ' ); Es perfectamente posible tener una captura todo de * y * para el método HTTP y la ruta de documentos.
Los encabezados de solicitud de HTTP se pueden combinar como:
WebMock.StubRequest( ' * ' , ' * ' ).WithHeader( ' Name ' , ' Value ' ); Se pueden lograr múltiples encabezados coincidentes de 2 maneras. El primero es simplemente encadenar con las llamadas WithHeader , por ejemplo:
WebMock.StubRequest( ' * ' , ' * ' )
.WithHeader( ' Header-1 ' , ' Value-1 ' )
.WithHeader( ' Header-2 ' , ' Value-2 ' ); Alternativamente, WithHeaders acepta una TStringList de pares de valores clave, por ejemplo:
var
Headers: TStringList;
begin
Headers := TStringList.Create;
Headers.Values[ ' Header-1 ' ] := ' Value-1 ' ;
Headers.Values[ ' Header-2 ' ] := ' Value-2 ' ;
WebMock.StubRequest( ' * ' , ' * ' ).WithHeaders(Headers);
end ;La solicitud HTTP puede coincidir con contenido como:
WebMock.StubRequest( ' * ' , ' * ' ).WithBody( ' String content. ' ); Las solicitudes HTTP se pueden igualar mediante datos de formulario como se envía con content-type de application/x-www-form-urlencoded . Se pueden combinar múltiples valores de campo coincidente. Por ejemplo:
WebMock.StubRequest( ' * ' , ' * ' )
.WithFormData( ' AField ' , ' A value. ' )
.WithFormData( ' AOtherField ' , ' Another value. ' ); Para simplemente igualar la presencia de un campo, se puede pasar un comodín * por el valor.
Nota: No puede hacer coincidir los datos de formulario ( WithFormData ) y el contenido del cuerpo ( WithBody ) al mismo tiempo. Especificar ambos dará como resultado la última llamada que sobrescribirá el Matcher anterior.
Hacer coincidir una solicitud por expresión regular puede ser útil para eliminar rutas dinámicas para un recurso relajante que involucra un nombre de recurso y una ID de recurso desconocida como /resource/999 . Tal solicitud podría ser robada por:
WebMock.StubRequest( ' GET ' , TRegEx.Create( ' ^/resource/d+$ ' ));Los encabezados coincidentes pueden lograrse de manera similar por:
WebMock.StubRequest( ' * ' , ' * ' )
.WithHeader( ' Accept ' , TRegEx.Create( ' video/.+ ' ));El contenido coincidente se puede realizar como:
WebMock.StubRequest( ' * ' , ' * ' )
.WithBody(TRegEx.Create( ' Hello ' ));El contenido de datos de formulario coincidente se puede realizar como:
WebMock.StubRequest( ' * ' , ' * ' )
.WithFormData( ' AField ' , TRegEx.Create( ' .* ' )); Nota: Asegúrese de agregar System.RegularExpressions a su cláusula de usos.
Las solicitudes HTTP pueden coincidir con los datos JSON como se envía con content-type de application/json usando WithJSON . Se pueden combinar múltiples valores de campo coincidente. Por ejemplo:
WebMock.StubRequest( ' * ' , ' * ' )
.WithJSON( ' ABoolean ' , True)
.WithJSON( ' AFloat ' , 0.123 )
.WithJSON( ' AInteger ' , 1 )
.WithJSON( ' AString ' , ' value ' ); El primer argumento puede ser un camino. Por ejemplo, en el siguiente JSON, los objects[0].key coincidiría con value 1 .
{
"objects" : [
{ "key" : " value 1 " },
{ "key" : " value 2 " }
]
}Nota: Los patrones de cadenas se pueden igualar pasando una expresión regular como segundo argumento. Por ejemplo:
WebMock.StubRequest( ' * ' , ' * ' )
.WithJSON( ' objects[0].key ' , TRegEx.Create( ' valuesd+ ' ));La solicitud HTTP puede coincidir con los valores de datos XML enviados. Por ejemplo:
WebMock.StubRequest( ' * ' , ' * ' )
.WithXML( ' /Object/Attr1 ' , ' Value 1 ' );El primer argumento es una expresión de XPath. El ejemplo anterior haría una coincidencia positiva contra el siguiente documento:
<? xml version = " 1.0 " encoding = " UTF-8 " ?>
< Object >
< Attr1 >Value 1</ Attr1 >
</ Object >El segundo argumento puede ser un valor booleano, flotante, entero o valor de cadena.
Si se requiere que la lógica coincida sea más compleja que la simple coincidencia, se puede proporcionar una función de predicado en la prueba para permitir la inspección/lógica personalizada para que coincida con una solicitud. La función de predicado anónimo recibirá un objeto IWebMockHTTPRequest para inspeccionar la solicitud. Si la función de predicado devuelve True entonces el stub se considerará como una coincidencia, si devuelve False no se coincidirá.
Ejemplo de stub con función de predicado:
WebMock.StubRequest(
function(ARequest: IWebMockHTTPRequest): Boolean
begin
Result := True; // Return False to ignore request.
end
); Por defecto, un estado de respuesta estará 200 OK para una solicitud retirada. Si se realiza una solicitud a TWebMock sin un trozo registrado, responderá 501 Not Implemented . Para especificar el estado de respuesta, use ToRespond .
WebMock.StubRequest( ' GET ' , ' / ' ).ToRespond(TWebMockResponseStatus.NotFound);Los encabezados se pueden agregar a un trozo de respuesta como:
WebMock.StubRequest( ' * ' , ' * ' )
.ToRespond.WithHeader( ' Header-1 ' , ' Value-1 ' ); Al igual que con el encabezado de solicitud, el encabezado de encabezado se puede especificar múltiples encabezados, ya sea a través del encadenamiento del método o utilizando el método WithHeaders .
WebMock.StubRequest( ' * ' , ' * ' ).ToRespond
.WithHeader( ' Header-1 ' , ' Value-1 ' )
.WithHeader( ' Header-2 ' , ' Value-2 ' );
/* or */
var
Headers: TStringList;
begin
Headers := TStringList.Create;
Headers.Values[ ' Header-1 ' ] := ' Value-1 ' ;
Headers.Values[ ' Header-2 ' ] := ' Value-2 ' ;
WebMock.StubRequest( ' * ' , ' * ' )
.ToRespond.WithHeaders(Headers);
end ; De manera predeterminada, una respuesta retirada devuelve un cuerpo de longitud cero con text/plain . El contenido de respuesta simple que se representa fácilmente como una string se puede establecer con WithBody .
WebMock.StubRequest( ' GET ' , ' / ' )
.ToRespond.WithBody( ' Text To Return ' );Si desea devolver un tipo de contenido específico, se puede especificar como el segundo argumento, por ejemplo,
WebMock.StubRequest( ' GET ' , ' / ' )
.ToRespond.WithBody( ' { "status": "ok" } ' , ' application/json ' ); Al eliminar las respuestas con contenido binario o grande, es probable que sea más fácil proporcionar el contenido como un archivo. Esto se puede lograr usando WithBodyFile que tiene la misma firma que WithBody pero el primer argumento es la ruta a un archivo.
WebMock.StubRequest( ' GET ' , ' / ' ).WithBodyFile( ' image.jpg ' ); Delphi-Webmocks intentarán establecer el tipo de contenido de acuerdo con la extensión del archivo. Si se desconoce el tipo de archivo, el tipo de contenido se predeterminará a application/octet-stream . El tipo de contenido se puede anular con el segundo argumento. p.ej
WebMock.StubRequest( ' GET ' , ' / ' ).WithBodyFile( ' file.myext ' , ' application/xml ' ); Nota: Un acceso de "gotcha" de "gotcha" en las pruebas es que la ubicación del archivo será relativa al ejecutable de prueba que, de manera predeterminada, utilizan el compilador de 32 bits de Windows a la carpeta Win32Debug . Para hacer referencia correctamente a un archivo llamado Content.txt en la carpeta del proyecto, la ruta será ....Content.txt .
A veces es útil responder dinámicamente a una solicitud. Por ejemplo:
WebMock.StubRequest( ' * ' , ' * ' )
.ToRespondWith(
procedure ( const ARequest: IWebMockHTTPRequest;
const AResponse: IWebMockResponseBuilder)
begin
AReponse
.WithStatus( 202 )
.WithHeader( ' header-1 ' , ' a-value ' )
.WithBody( ' Some content... ' );
end
);Esto permite la prueba de características que requieren una inspección más profunda de la solicitud o para reflejar los valores de la solicitud en la respuesta. Por ejemplo:
WebMock.StubRequest( ' GET ' , ' /echo_header ' )
.ToRespondWith(
procedure ( const ARequest: IWebMockHTTPRequest;
const AResponse: IWebMockHTTPResponseBuilder)
begin
AResponse.WithHeader( ' my-header ' , ARequest.Headers.Values[ ' my-header ' ]);
end
);También puede ser útil para simular fallas para una serie de intentos antes de devolver un éxito. Por ejemplo:
var LRequestCount := 0 ;
WebMock.StubRequest( ' GET ' , ' /busy_endpoint ' )
.ToRespondWith(
procedure ( const ARequest: IWebMockHTTPRequest;
const AResponse: IWebMockHTTPResponseBuilder)
begin
Inc(LRequestCount);
if LRequestCount < 3 then
AResponse.WithStatus( 408 , ' Request Timeout ' )
else
AResponse.WithStatus( 200 , ' OK ' );
end
); Si necesita borrar los trozos registrados actuales, puede llamar ResetStubRegistry o Reset en la instancia de TwebMock. El método Reset general devolverá la instancia de Twebmock a un estado en blanco, incluido el vaciado del registro STUB. El ResetStubRegistry más específico, como se sugirió, solo clara solo el Registro STUB.
Todas y cada una de las solicitudes hechas de la instancia de Twebmock se registran en la propiedad History . Las entradas del historial contienen toda la información clave de la solicitud web: método; Requesturi; Encabezados; y cuerpo.
Es posible escribir afirmaciones basadas en el historial de solicitudes, por ejemplo:
WebClient.Get(WebMock.URLFor( ' document ' ));
Assert.AreEqual( ' GET ' , WebMock.History.Last.Method);
Assert.AreEqual( ' /document ' , WebMock.History.Last.RequestURI);Nota: Si se encuentra escribiendo afirmaciones en esta mansión, debe echar un vistazo a las afirmaciones de solicitud que proporciona una forma más concisa de definir estas afirmaciones.
Si necesita borrar el historial de solicitudes, puede llamar ResetHistory o Reset en la instancia de Twebmock. El método Reset general devolverá la instancia de Twebmock a un estado en blanco, incluido el vaciado de la historia. El ResetHistory más específico, según sugerido, solo clara solo la historia.
Además de utilizar las afirmaciones DUNITX para validar su código, como se esperaba, también puede usar las afirmaciones de solicitudes para verificar si las solicitudes que espera que su código se ejecute donde se ejecute como se esperaba.
Una simple afirmación de solicitud:
WebClient.Get(WebMock.URLFor( ' / ' ));
WebMock.Assert.Get( ' / ' ).WasRequested; // Passes Al igual que con la solicitud de solicitud, puede hacer coincidir las solicitudes por método HTTP, URI, parámetros de consulta, encabezados y contenido del cuerpo (incluso WithJSON y WithXML ).
WebMock.Assert
.Patch( ' /resource`)
.WithQueryParam( ' ParamName ' , ' Value ' )
.WithHeader( ' Content- Type ' , ' application/json ' )
.WithBody( ' { "resource": { "propertyA": "Value" } } ' )
.WasRequested; Cualquier cosa que se pueda afirmar positivamente ( WasRequested ) también puede afirmarse negativamente con WasNotRequested . Esto es útil para verificar que su código no realice solicitudes adicionales no deseadas.
Este proyecto sigue a versiones semánticas.
Copyright © 2019-2024 Richard Hatherall [email protected]
WebMocks se distribuye bajo los términos de la licencia Apache (versión 2.0).
Vea la licencia para más detalles.