Mocker é uma biblioteca escrita no SWIFT, que possibilita zombar de solicitações de dados usando um URLProtocol
personalizado.
Executar todos os seus testes de unidade de solicitação de dados offline ?
URLSession
usando uma classe de protocolo personalizada Alamofire
Os testes de unidade são escritos para o Mocker
, que pode ajudá -lo a ver como funciona.
O zombador será ativado automaticamente para o sistema de carregamento de URL padrão como URLSession.shared
depois de registrar sua primeira Mock
.
Para fazê -lo funcionar com sua URLSession
personalizada, o MockingURLProtocol
precisa ser registrado:
let configuration = URLSessionConfiguration . default
configuration . protocolClasses = [ MockingURLProtocol . self ]
let urlSession = URLSession ( configuration : configuration )
Muito parecido com o registro em uma URLSession
personalizada.
let configuration = URLSessionConfiguration . af . default
configuration . protocolClasses = [ MockingURLProtocol . self ]
let sessionManager = Alamofire . Session ( configuration : configuration )
É recomendável criar uma classe com todos os seus dados zombados acessíveis. Um exemplo disso pode ser encontrado nos testes de unidade deste projeto:
public final class MockedData {
public static let botAvatarImageResponseHead : Data = try ! Data ( contentsOf : Bundle ( for : MockedData . self ) . url ( forResource : " Resources/Responses/bot-avatar-image-head " , withExtension : " data " ) ! )
public static let botAvatarImageFileUrl : URL = Bundle ( for : MockedData . self ) . url ( forResource : " wetransfer_bot_avater " , withExtension : " png " ) !
public static let exampleJSON : URL = Bundle ( for : MockedData . self ) . url ( forResource : " Resources/JSON Files/example " , withExtension : " json " ) !
}
let originalURL = URL ( string : " https://www.wetransfer.com/example.json " ) !
let mock = Mock ( url : originalURL , contentType : . json , statusCode : 200 , data : [
. get : try ! Data ( contentsOf : MockedData . exampleJSON ) // Data containing the JSON response
] )
mock . register ( )
URLSession . shared . dataTask ( with : originalURL ) { ( data , response , error ) in
guard let data = data , let jsonDictionary = ( try ? JSONSerialization . jsonObject ( with : data , options : [ ] ) ) as? [ String : Any ] else {
return
}
// jsonDictionary contains your JSON sample file data
// ..
} . resume ( )
let originalURL = URL ( string : " https://www.wetransfer.com/api/foobar " ) !
var request = URLRequest ( url : originalURL )
request . httpMethod = " PUT "
let mock = Mock ( request : request , statusCode : 204 )
mock . register ( )
URLSession . shared . dataTask ( with : originalURL ) { ( data , response , error ) in
// ....
} . resume ( )
Alguns URLs como URLs de autenticação contêm registros de data e hora ou UUIDs na consulta. Para zombar deles, você pode ignorar a consulta para um certo URL:
/// Would transform to "https://www.example.com/api/authentication" for example.
let originalURL = URL ( string : " https://www.example.com/api/authentication?oauth_timestamp=151817037 " ) !
let mock = Mock ( url : originalURL , ignoreQuery : true , contentType : . json , statusCode : 200 , data : [
. get : try ! Data ( contentsOf : MockedData . exampleJSON ) // Data containing the JSON response
] )
mock . register ( )
URLSession . shared . dataTask ( with : originalURL ) { ( data , response , error ) in
guard let data = data , let jsonDictionary = ( try ? JSONSerialization . jsonObject ( with : data , options : [ ] ) ) as? [ String : Any ] else {
return
}
// jsonDictionary contains your JSON sample file data
// ..
} . resume ( )
let imageURL = URL ( string : " https://www.wetransfer.com/sample-image.png " ) !
Mock ( fileExtensions : " png " , contentType : . imagePNG , statusCode : 200 , data : [
. get : try ! Data ( contentsOf : MockedData . botAvatarImageFileUrl )
] ) . register ( )
URLSession . shared . dataTask ( with : imageURL ) { ( data , response , error ) in
let botAvatarImage : UIImage = UIImage ( data : data! ) ! // This is the image from your resources.
} . resume ( )
let exampleURL = URL ( string : " https://www.wetransfer.com/api/endpoint " ) !
Mock ( url : exampleURL , contentType : . json , statusCode : 200 , data : [
. head : try ! Data ( contentsOf : MockedData . headResponse ) ,
. get : try ! Data ( contentsOf : MockedData . exampleJSON )
] ) . register ( )
URLSession . shared . dataTask ( with : exampleURL ) { ( data , response , error ) in
// data is your mocked data
} . resume ( )
Além da compilação já construída nas implementações estáticas DataType
, é possível criar as personalizadas que serão usadas como o valor da chave do cabeçalho Content-Type
.
let xmlURL = URL ( string : " https://www.wetransfer.com/sample-xml.xml " ) !
Mock ( fileExtensions : " png " , contentType : . init ( name : " xml " , headerValue : " text/xml " ) , statusCode : 200 , data : [
. get : try ! Data ( contentsOf : MockedData . sampleXML )
] ) . register ( )
URLSession . shared . dataTask ( with : xmlURL ) { ( data , response , error ) in
let sampleXML : Data = data // This is the xml from your resources.
} . resume (
Às vezes, você deseja testar se o cancelamento de solicitações está funcionando. Nesse caso, a solicitação ridicularizada não deve terminar imediatamente e você precisa de um atraso. Isso pode ser adicionado facilmente:
let exampleURL = URL ( string : " https://www.wetransfer.com/api/endpoint " ) !
var mock = Mock ( url : exampleURL , contentType : . json , statusCode : 200 , data : [
. head : try ! Data ( contentsOf : MockedData . headResponse ) ,
. get : try ! Data ( contentsOf : MockedData . exampleJSON )
] )
mock . delay = DispatchTimeInterval . seconds ( 5 )
mock . register ( )
Às vezes, você quer zombar de URLs curtos ou outros URLs de redirecionamento. Isso é possível salvando a resposta e zombando do local de redirecionamento, que pode ser encontrado dentro da resposta:
Date: Tue, 10 Oct 2017 07:28:33 GMT
Location: https://wetransfer.com/redirect
Ao criar uma simulação para o URL curto e o URL de redirecionamento, você pode zombar do redirecionamento e testar esse comportamento:
let urlWhichRedirects : URL = URL ( string : " https://we.tl/redirect " ) !
Mock ( url : urlWhichRedirects , contentType : . html , statusCode : 200 , data : [ . get : try ! Data ( contentsOf : MockedData . redirectGET ) ] ) . register ( )
Mock ( url : URL ( string : " https://wetransfer.com/redirect " ) ! , contentType : . json , statusCode : 200 , data : [ . get : try ! Data ( contentsOf : MockedData . exampleJSON ) ] ) . register ( )
À medida que o zombador captura todos os URLs por padrão quando registrado, você pode acabar com um fatalError
jogado nos casos em que não precisa de uma solicitação ridicularizada. Nesse caso, você pode ignorar o URL:
let ignoredURL = URL ( string : " https://www.wetransfer.com " ) !
// Ignore any requests that exactly match the URL
Mocker . ignore ( ignoredURL )
// Ignore any requests that match the URL, with any query parameters
// e.g. https://www.wetransfer.com?foo=bar would be ignored
Mocker . ignore ( ignoredURL , matchType : . ignoreQuery )
// Ignore any requests that begin with the URL
// e.g. https://www.wetransfer.com/api/v1 would be ignored
Mocker . ignore ( ignoredURL , matchType : . prefix )
No entanto, se você precisar do zombador para capturar apenas URLs ridicularizados e ignorar todos os outros URLs, poderá definir o atributo mode
para .optin
.
Mocker . mode = . optin
Se você deseja definir o modo original de volta, basta defini -lo como .optout
.
Mocker . mode = . optout
Você pode solicitar uma Mock
para retornar um erro, permitindo o teste do tratamento de erros.
Mock ( url : originalURL , contentType : . json , statusCode : 500 , data : [ . get : Data ( ) ] ,
requestError : TestExampleError . example ) . register ( )
URLSession . shared . dataTask ( with : originalURL ) { ( data , urlresponse , err ) in
XCTAssertNil ( data )
XCTAssertNil ( urlresponse )
XCTAssertNotNil ( err )
if let err = err {
// there's not a particularly elegant way to verify an instance
// of an error, but this is a convenient workaround for testing
// purposes
XCTAssertEqual ( " example " , String ( describing : err ) )
}
expectation . fulfill ( )
} . resume ( )
Você pode se registrar em retornos de chamada Mock
para facilitar o teste.
var mock = Mock ( url : request . url! , contentType : . json , statusCode : 200 , data : [ . post : Data ( ) ] )
mock . onRequestHandler = OnRequestHandler ( httpBodyType : [ [ String : String ] ] . self , callback : { request , postBodyArguments in
XCTAssertEqual ( request . url , mock . request . url )
XCTAssertEqual ( expectedParameters , postBodyArguments )
onRequestExpectation . fulfill ( )
} )
mock . completion = {
endpointIsCalledExpectation . fulfill ( )
}
mock . register ( )
Em vez de definir a completion
e onRequest
você também pode usar as expectativas:
var mock = Mock ( url : url , contentType : . json , statusCode : 200 , data : [ . get : Data ( ) ] )
let requestExpectation = expectationForRequestingMock ( & mock )
let completionExpectation = expectationForCompletingMock ( & mock )
mock . register ( )
URLSession . shared . dataTask ( with : URLRequest ( url : url ) ) . resume ( )
wait ( for : [ requestExpectation , completionExpectation ] , timeout : 2.0 )
Você pode limpar todas as manchas registradas:
Mocker . removeAll ( )
Cartago é um gerente de dependência descentralizado que cria suas dependências e fornece estruturas binárias.
Você pode instalar Cartago com Homebrew usando o seguinte comando:
$ brew update
$ brew install carthage
Para integrar o zombador no seu projeto Xcode usando o Cartago, especifique -o no seu Cartfile
:
github "WeTransfer/Mocker" ~> 3.0.0
Execute carthage update
para criar a estrutura e arrastar o Mocker.framework
construído para o seu projeto Xcode.
O Swift Package Manager é uma ferramenta para gerenciar a distribuição do código SWIFT. Está integrado ao sistema Swift Build para automatizar o processo de download, compilação e vinculação dependências.
Adicione zombador como um pacote ao seu arquivo Package.swift
e especifique -o como uma dependência do destino em que você deseja usá -lo.
import PackageDescription
let package = Package (
name : " MyProject " ,
platforms : [
. macOS ( . v10_15 )
] ,
dependencies : [
. package ( url : " https://github.com/WeTransfer/Mocker.git " , . upToNextMajor ( from : " 3.0.0 " ) )
] ,
targets : [
. target (
name : " MyProject " ,
dependencies : [ " Mocker " ] ) ,
. testTarget (
name : " MyProjectTests " ,
dependencies : [ " MyProject " ] ) ,
]
)
Para adicionar zombar como uma dependência ao seu projeto Xcode, selecione Arquivo> Pacotes Swift> Adicionar dependência do pacote e insira o URL do repositório.
Se você receber o seguinte erro: não é possível encontrar a biblioteca de ligação automática xctest e xctestswiftSupport , defina a seguinte propriedade em opções de construção de não como sim.
Enable_testing_search_paths para sim
Se você preferir não usar nenhum dos gerentes de dependência acima mencionados, poderá integrar zombar manualmente seu projeto.
Abra o terminal, cd
no seu diretório de projeto de nível superior e execute o seguinte comando "se" seu projeto não for inicializado como um repositório Git:
$ git init
Adicionar zombar como um submódulo Git executando o seguinte comando:
$ git submodule add https://github.com/WeTransfer/Mocker.git
Abra a nova pasta Mocker
e arraste o Mocker.xcodeproj
para o navegador do projeto do projeto Xcode do seu aplicativo.
Deve aparecer aninhado sob o ícone do projeto azul do seu aplicativo. Se está acima ou abaixo de todos os outros grupos Xcode, não importa.
Selecione o Mocker.xcodeproj
no navegador do projeto e verifique se a meta de implantação corresponde à do seu destino de aplicativo.
Em seguida, selecione seu projeto de aplicativo no projeto Navigator (ícone do projeto azul) para navegar até a janela de configuração de destino e selecione o destino do aplicativo na direção "alvos" na barra lateral.
Na barra de guias na parte superior dessa janela, abra o painel "geral".
Clique no botão +
na seção "Binários incorporados".
Selecione Mocker.framework
.
E é isso!
O
Mocker.framework
é adicionado automaticamente como uma dependência de destino, estrutura vinculada e estrutura incorporada em uma fase de criação de arquivos de cópia, o que é tudo o que você precisa para criar no simulador e no dispositivo.
Consulte Changelog.md para obter uma lista de alterações.
Mocker está disponível sob a licença do MIT. Consulte o arquivo de licença para obter mais informações.