Biblioteca para Stubbing e Definir expectativas nas solicitações HTTP em Delphi com Dunitx.
* WebMocks foi desenvolvido no Delphi 10.3 (Rio) e 10.4 (Sydney) e até a versão 3.0 ser compatível com o XE8. Como o webmocks faz uso da biblioteca System.Net introduzida com XE8, ele não será compatível com versões anteriores. Se você precisar de instalação nas versões Delphi antes de 10.3, você deve instalar a versão 2.0.0.
WebMocks 3.2.0 está disponível no gerente de pacotes da Embarcadero para o Delphi Getit. Se você tem uma versão recente do Delphi, incluindo o Getit, esse deve ser o método de instalação preferido.
Agora, os webmocks devem estar listados no Delphinus Package Manager.
Certifique -se de reiniciar o Delphi após a instalação do Via Delphinus, caso contrário, as unidades não poderão ser encontradas em seus projetos de teste.
Source extraído ao "caminho da biblioteca" e "caminho de navegação". Se você quiser uma introdução suave aos webmocks para a Delphi, há uma série de artigos publicados no Dev começando com o teste de clientes HTTP em Delphi com Dunitx e WebMocks.
Delphi-Webmocks-Demos contém um conjunto de demonstrações para acompanhar os artigos.
A versão 2 descartou o Delphi. namespace de todas as unidades. Qualquer projeto atualizado para a versão 2 ou posterior precisará abandonar o Delphi. Prefixo de qualquer unidade de webmocks incluída.
No seu arquivo de unidade de teste, são necessárias algumas etapas simples.
WebMock aos uses da sua interface.TestFixture , use Setup e TearDown para criar/destruir uma instância do 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 padrão, TWebMock se ligará a um início dinamicamente atribuído em 8080 . Esse comportamento pode ser substituído especificando uma porta na criação.
WebMock := TWebMock.Create( 8088 ); O uso do WebMock.URLFor Function em seus testes é simplificar a construção de um URL válido. A propriedade Port contém a porta ligada atual e a propriedade BaseURL contém um URL válido para a raiz do servidor.
A forma mais simples de correspondência de solicitação e ponto de partida para todos os stubs de solicitação é pelo método HTTP e caminho do documento. Por exemplo, matar o verbo http GET à raiz do servidor / é alcançado por:
WebMock.StubRequest( ' GET ' , ' / ' ); O uso de um único caractere de cartão selvagem * pode ser usado para corresponder a qualquer solicitação. Por exemplo, para corresponder a todas as solicitações POST , independentemente do caminho do documento que você pode usar:
WebMock.StubRequest( ' POST ' , ' * ' );Da mesma forma, para corresponder a qualquer método HTTP para um determinado caminho que você pode usar:
WebMock.StubRequest( ' * ' , ' /path ' ); É perfeitamente possível ter uma captura de * e * para o método HTTP e o caminho do documento.
Os cabeçalhos de solicitação HTTP podem ser correspondidos como:
WebMock.StubRequest( ' * ' , ' * ' ).WithHeader( ' Name ' , ' Value ' ); A correspondência de vários cabeçalhos pode ser alcançada de duas maneiras. O primeiro é simplesmente encadear chamadas WithHeader , por exemplo:
WebMock.StubRequest( ' * ' , ' * ' )
.WithHeader( ' Header-1 ' , ' Value-1 ' )
.WithHeader( ' Header-2 ' , ' Value-2 ' ); Como alternativa, WithHeaders aceita uma lista de TStringList de pares de valores-chave, por exemplo:
var
Headers: TStringList;
begin
Headers := TStringList.Create;
Headers.Values[ ' Header-1 ' ] := ' Value-1 ' ;
Headers.Values[ ' Header-2 ' ] := ' Value-2 ' ;
WebMock.StubRequest( ' * ' , ' * ' ).WithHeaders(Headers);
end ;A solicitação HTTP pode ser correspondida por conteúdo como:
WebMock.StubRequest( ' * ' , ' * ' ).WithBody( ' String content. ' ); As solicitações HTTP podem ser correspondidas pelo Form-Data, conforme enviado com content-type do application/x-www-form-urlencoded . Vários valores de campo correspondentes podem ser combinados. Por exemplo:
WebMock.StubRequest( ' * ' , ' * ' )
.WithFormData( ' AField ' , ' A value. ' )
.WithFormData( ' AOtherField ' , ' Another value. ' ); Para simplesmente corresponder à presença de um campo, um curinga * pode ser passado pelo valor.
NOTA: Você não pode corresponder aos dados de formulário ( WithFormData ) e ao conteúdo do corpo ( WithBody ) ao mesmo tempo. A especificação de ambos resultará na última chamada que substitui o fósforo anterior.
A correspondência de uma solicitação por expressão regular pode ser útil para matar rotas dinâmicas para um recurso RESTful envolvendo um nome de recurso e um ID de recurso desconhecido, como /resource/999 . Tal pedido pode ser extraído por:
WebMock.StubRequest( ' GET ' , TRegEx.Create( ' ^/resource/d+$ ' ));Os cabeçalhos correspondentes podem da mesma forma que alcançados por:
WebMock.StubRequest( ' * ' , ' * ' )
.WithHeader( ' Accept ' , TRegEx.Create( ' video/.+ ' ));Conteúdo correspondente pode ser realizado como:
WebMock.StubRequest( ' * ' , ' * ' )
.WithBody(TRegEx.Create( ' Hello ' ));O conteúdo de dados de formulários correspondente pode ser executado como:
WebMock.StubRequest( ' * ' , ' * ' )
.WithFormData( ' AField ' , TRegEx.Create( ' .* ' )); NOTA: Certifique -se de adicionar System.RegularExpressions à sua cláusula de uso.
As solicitações HTTP podem ser correspondidas pelos dados JSON, conforme enviado com content-type do application/json usando WithJSON . Vários valores de campo correspondentes podem ser combinados. Por exemplo:
WebMock.StubRequest( ' * ' , ' * ' )
.WithJSON( ' ABoolean ' , True)
.WithJSON( ' AFloat ' , 0.123 )
.WithJSON( ' AInteger ' , 1 )
.WithJSON( ' AString ' , ' value ' ); O primeiro argumento pode ser um caminho. Por exemplo, no seguinte JSON, o caminho objects[0].key corresponderia value 1 .
{
"objects" : [
{ "key" : " value 1 " },
{ "key" : " value 2 " }
]
}NOTA: Os padrões de strings podem ser correspondidos passando uma expressão regular como o segundo argumento. Por exemplo:
WebMock.StubRequest( ' * ' , ' * ' )
.WithJSON( ' objects[0].key ' , TRegEx.Create( ' valuesd+ ' ));A solicitação HTTP pode ser correspondida pelos valores de dados XML enviados. Por exemplo:
WebMock.StubRequest( ' * ' , ' * ' )
.WithXML( ' /Object/Attr1 ' , ' Value 1 ' );O primeiro argumento é uma expressão XPath. O exemplo anterior faria uma correspondência positiva contra o seguinte documento:
<? xml version = " 1.0 " encoding = " UTF-8 " ?>
< Object >
< Attr1 >Value 1</ Attr1 >
</ Object >O segundo argumento pode ser um valor booleano, flutuante, número inteiro ou string.
Se a lógica correspondente for necessária para ser mais complexa que a correspondência simples, uma função de predicado pode ser fornecida no teste para permitir inspeção/lógica personalizada para corresponder a uma solicitação. A função de predicado anônimo receberá um objeto IWebMockHTTPRequest para inspecionar a solicitação. Se a função predicada retornar True , o stub será considerado uma correspondência, se retornar False ele não será correspondido.
Exemplo de stub com função de predicado:
WebMock.StubRequest(
function(ARequest: IWebMockHTTPRequest): Boolean
begin
Result := True; // Return False to ignore request.
end
); Por padrão, um status de resposta estará 200 OK para uma solicitação de manchas. Se uma solicitação for feita para TWebMock sem um stub registrado, ele responderá 501 Not Implemented . Para especificar o status da resposta, use ToRespond .
WebMock.StubRequest( ' GET ' , ' / ' ).ToRespond(TWebMockResponseStatus.NotFound);Cabeçalhos podem ser adicionados a um stub de resposta como:
WebMock.StubRequest( ' * ' , ' * ' )
.ToRespond.WithHeader( ' Header-1 ' , ' Value-1 ' ); Como no cabeçalho da solicitação, a correspondência de vários cabeçalhos pode ser especificada por meio de encadeamento de métodos ou usando o 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 ; Por padrão, uma resposta estuprada retorna um corpo de comprimento zero com text/plain do tipo conteúdo. O conteúdo simples de resposta que é facilmente representado como uma string pode ser definido com WithBody .
WebMock.StubRequest( ' GET ' , ' / ' )
.ToRespond.WithBody( ' Text To Return ' );Se você quiser retornar um tipo de conteúdo específico, ele pode ser especificado como o segundo argumento, por exemplo,
WebMock.StubRequest( ' GET ' , ' / ' )
.ToRespond.WithBody( ' { "status": "ok" } ' , ' application/json ' ); Ao extrair respostas com conteúdo binário ou grande, provavelmente é mais fácil fornecer o conteúdo como um arquivo. Isso pode ser alcançado usando WithBodyFile , que tem a mesma assinatura que WithBody , mas o primeiro argumento é o caminho para um arquivo.
WebMock.StubRequest( ' GET ' , ' / ' ).WithBodyFile( ' image.jpg ' ); Os Delphi-Webmocks tentarão definir o tipo de conteúdo de acordo com a extensão do arquivo. Se o tipo de arquivo for desconhecido, o tipo de conteúdo será padrão para application/octet-stream . O tipo de conteúdo pode ser substituído pelo segundo argumento. por exemplo
WebMock.StubRequest( ' GET ' , ' / ' ).WithBodyFile( ' file.myext ' , ' application/xml ' ); NOTA: Um "pegadinha" de acesso a arquivos nos testes é a localização do arquivo em relação ao executável do teste que, por padrão, usando o compilador Windows de 32 bits será emitido para a pasta Win32Debug . Para referenciar corretamente um arquivo chamado Content.txt na pasta do projeto, o caminho será ....Content.txt .
Às vezes, é útil responder dinamicamente a uma solicitação. Por exemplo:
WebMock.StubRequest( ' * ' , ' * ' )
.ToRespondWith(
procedure ( const ARequest: IWebMockHTTPRequest;
const AResponse: IWebMockResponseBuilder)
begin
AReponse
.WithStatus( 202 )
.WithHeader( ' header-1 ' , ' a-value ' )
.WithBody( ' Some content... ' );
end
);Isso permite o teste de recursos que requerem inspeção mais profunda da solicitação ou refletir valores da solicitação de volta na resposta. Por exemplo:
WebMock.StubRequest( ' GET ' , ' /echo_header ' )
.ToRespondWith(
procedure ( const ARequest: IWebMockHTTPRequest;
const AResponse: IWebMockHTTPResponseBuilder)
begin
AResponse.WithHeader( ' my-header ' , ARequest.Headers.Values[ ' my-header ' ]);
end
);Também pode ser útil para simular falhas para várias tentativas antes de retornar um sucesso. Por exemplo:
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
); Se você precisar limpar os stubs atuais registrados, poderá ligar para ResetStubRegistry ou Reset na instância do twebmock. O método Reset geral retornará a instância do Twebmock a um estado em branco, incluindo o esvaziamento do registro do Stub. O ResetStubRegistry mais específico, conforme sugerido, limpará apenas o registro do Stub.
Toda e qualquer solicitação feita da instância do Twebmock é registrada na propriedade History . As entradas de histórico contêm todas as principais informações da solicitação da Web: método; Requesturi; Cabeçalhos; e corpo.
É possível escrever afirmações com base no histórico de solicitações, por exemplo:
WebClient.Get(WebMock.URLFor( ' document ' ));
Assert.AreEqual( ' GET ' , WebMock.History.Last.Method);
Assert.AreEqual( ' /document ' , WebMock.History.Last.RequestURI);Nota: Se você estiver escrevendo afirmações nesta mansão, você deve dar uma olhada nas afirmações de solicitação que fornecem uma maneira mais concisa de definir essas afirmações.
Se você precisar limpar o histórico de solicitações, poderá ligar para ResetHistory ou Reset na instância do Twebmock. O método Reset geral retornará a instância do Twebmock a um estado em branco, incluindo o esvaziamento da história. O ResetHistory mais específico será sugerido apenas a história.
Além de usar as afirmações DunitX para validar seu código como esperado, você também pode usar as afirmações de solicitação para verificar se as solicitações que você espera que seu código seja executado onde executado conforme o esperado.
Uma afirmação simples de solicitação:
WebClient.Get(WebMock.URLFor( ' / ' ));
WebMock.Assert.Get( ' / ' ).WasRequested; // Passes Assim como a Stubbing de solicitação, você pode corresponder solicitações pelo método HTTP, URI, parâmetros de consulta, cabeçalhos e conteúdo corporal (incluindo WithJSON e WithXML ).
WebMock.Assert
.Patch( ' /resource`)
.WithQueryParam( ' ParamName ' , ' Value ' )
.WithHeader( ' Content- Type ' , ' application/json ' )
.WithBody( ' { "resource": { "propertyA": "Value" } } ' )
.WasRequested; Qualquer coisa que possa ser afirmada positivamente ( WasRequested ) também pode ser afirmada negativamente com WasNotRequested . Isso é útil para verificar seu código não está executando solicitações extras indesejadas.
Este projeto segue a versão semântica.
Copyright © 2019-2024 Richard Hatherall [email protected]
O WebMocks é distribuído nos termos da licença Apache (versão 2.0).
Consulte a licença para obter detalhes.