iOS - arquivo 'MyProject-Swift.h' não encontrado ao executar testes de unidade para Swift

94

Estou tentando configurar o Teste de Unidade para meu projeto. É um aplicativo Objective-C existente, ao qual adicionei recentemente uma classe Swift. Eu configurei os arquivos 'MyProject-Swift.h' e Swift Bridging (ambos 'MyProject' e 'MyProjectTest') e sou capaz de construir e executar o aplicativo perfeitamente usando os códigos Objective-C e Swift.

No entanto, agora quero executar alguns testes de unidade na nova classe Swift. Eu configurei meu arquivo de teste e ele se parece com o seguinte:

MySwiftClassTests.swift:

import UIKit
import XCTest
import MyProject

class MySwiftClassTests: XCTestCase {

    override func setUp() {
        super.setUp()
        // Put setup code here. This method is called before the invocation of each test method in the class.
    }

    override func tearDown() {
        // Put teardown code here. This method is called after the invocation of each test method in the class.
        super.tearDown()
    }

    func testExample() {
        // This is an example of a functional test case.
        XCTAssert(true, "Pass")
    }

    func testPerformanceExample() {
        // This is an example of a performance test case.
        self.measureBlock() {
            // Put the code you want to measure the time of here.
        }
    }

}

Recebo este erro ao executar o aplicativo como Teste:

'MyProject-Swift.h' file not found

Não sei por que isso acontece apenas ao tentar executar os testes. Alguma sugestão?

JimmyJammed
fonte
1
Adicionar atualizações sobre isso? Estou enfrentando o mesmo problema ...
hyouuu
1
@Coveloper - Como você pode definir os alvos para o arquivo '-Swift.h'? Não é um arquivo real que fica no projeto, mas sim compilado pelo Xcode na construção.
JimmyJammed
1
Aqui está uma atualização para o meu comentário "Eu também recebo o erro de arquivo 'MyProject-Swift.h' não encontrado ...": Eu encontrei uma solução alternativa definindo o nome do módulo do produto do destino MyProjectTests como MyProject em vez de MyProjectTests. Portanto, agora ambos os destinos (MyProject e MyProjectTests) têm o mesmo nome de módulo de produto. Isso é estranho, mas funciona e é de baixo risco, pois é o alvo do Teste. Devo mencionar que o nome do meu projeto é na verdade como My-Project, portanto, My_Project é o nome do módulo real.)
finneycanhelp
6
O arquivo "MyProject-Swift.h" é gerado em "$ (TARGET_TEMP_DIR) /../$ (PROJECT_NAME) .build / DerivedSources". Acabo adicionando isso aos Caminhos de pesquisa de cabeçalho para o meu alvo de teste de unidade.
gagarwal
1
@gagarwal Adicionar "$ (TARGET_TEMP_DIR) /../$ (PROJECT_NAME) .build / DerivedSources" aos Caminhos de Pesquisa de Cabeçalho para meu alvo de Teste de Unidade funcionou. :) Faça uma resposta SO a partir desse comentário e eu posso recompensá-lo com a recompensa, além de deixar claro para os outros que essa é uma ótima resposta.
finneycanhelp

Respostas:

148

O arquivo "MyProject-Swift.h" é gerado no seguinte caminho:

"$(TARGET_TEMP_DIR)/../$(PROJECT_NAME).build/DerivedSources"

Eu acabo adicionando isso aos Caminhos de pesquisa de cabeçalho para o meu alvo de teste de unidade.

Além disso, como @hyouuu apontou ser o problema conhecido, espero que a Apple forneça uma boa solução para eles. Até eu acreditar que precisamos usar a solução acima.

https://developer.apple.com/library/content/documentation/Xcode/Conceptual/RN-Xcode-Archive/Chapters/xc6_release_notes.html

gagarwal
fonte
Funcionou como um encanto!
DonnaLea
Impressionante! Não sei por que a Apple não menciona isso como uma solução alternativa. Também estou surpreso por não haver mais pessoas com esse problema. Qualquer pessoa com um projeto Obj-C existente convertendo coisas para Swift gradualmente encontrará esse problema.
mluisbrown
@fabb não é verdade - o TARGET_NAME é geralmente algo parecido <Product Name> Testscom o seu alvo de teste. No entanto, esta solução não funciona se o nome do seu produto tiver espaços. Veja minha resposta abaixo para uma solução.
Christopher Pickslay
2
Apenas uma observação, eu tive que adicionar o caminho de pesquisa e defini-lo como "recursivo" especificamente. Pode ser óbvio, mas não funcionou algumas vezes até eu fazer isso; Presumo que vá para subpastas então.
Miro,
1
Para o meu projeto, $(TARGET_TEMP_DIR)não funcionou. Acabei usando$CONFIGURATION_TEMP_DIR/{myTargetName}.build/DerivedSources
Jordan Bondo
32

Obrigado a @gagarwal por descobrir isso. Em nosso caso, o nome do produto tem um espaço, que está reduzido $PROJECT_NAME, então tive que codificá-lo. Além disso, usando em $CONFIGURATION_TEMP_DIRvez de $TARGET_TEMP_DIR, você pode remover o diretório pai ( ../) do caminho. Portanto, a solução é adicionar o seguinte aos Caminhos de pesquisa de cabeçalho em seu destino de teste:

"$(CONFIGURATION_TEMP_DIR)/Product Name With Spaces.build/DerivedSources"

Ou, se o seu produto não contiver espaços:

"$(CONFIGURATION_TEMP_DIR)/$(PROJECT_NAME).build/DerivedSources"
Christopher Pickslay
fonte
Também resolve o problema de teste de unidade de classes codegen de Core Data.
Elise van Looij
14

Vimos na nota de versão do Xcode 6.1 que este é um problema conhecido ... sinal ... Pesquise "-swift.h" na nota de versão https://developer.apple.com/library/content/documentation/Xcode /Conceptual/RN-Xcode-Archive/Chapters/xc6_release_notes.html

Os testes escritos em Objective-C não podem importar o cabeçalho de interfaces gerado pelo Swift ($ (PRODUCT_MODULE_NAME) -Swift.h) para destinos de aplicativo e, portanto, não podem ser usados ​​para testar o código que requer esse cabeçalho.

Os testes de código Swift devem ser escritos em Swift. Os testes escritos em Objective-C para destinos de estrutura podem acessar as interfaces geradas pelo Swift importando o módulo de estrutura usando @import FrameworkName ;. (16931027)

Consulte a solução alternativa de @gagarwal abaixo que FUNCIONA!

Hyouuu
fonte
8

Eu tive um problema semelhante ao seu, eu acho; aqui estava minha configuração.

Eu tinha um objeto definido no Swift:

// file Foo.swift
@objc public class Foo {
    // ...
}

Essa classe foi então usada no inicializador de um objeto Objective-C:

// file Bar.h
#import "MyProject-Swift.h"

@interface Bar: NSObject

- (instancetype)initWithFoo:(Foo *)foo;

@end

Isso fez com que meus testes de unidade Barnão fossem compilados, já que o MyProject-Swift.hcabeçalho não é real e o destino do teste de unidade não pode vê-lo. A nota de lançamento compartilhada por @hyouuu está certa - mas não estou testando uma classe Swift, estou testando uma classe Objective-C!

Consegui consertar isso alterando o arquivo de cabeçalho para Barusar uma referência de classe direta:

// file Bar.h
@class Foo;

@interface Bar: NSObject

- (instancetype)initWithFoo:(Foo *)foo;

@end

Eu, então, incluído MyProject-Swift.hno Bar.m, e tudo funcionou - meus testes de Objective-C objetos escrito em Objective-C compilado corretamente e continuou correndo, e eu poderia escrever novos testes para Swift objetos em Swift.

Espero que isto ajude!

dpassage
fonte
Sua solução não permite o uso Fooda API de dentro Bar.m.
Yevhen Dubinin
2
Claro que sim - é isso que você inclui MyProject-Swift.hno .marquivo.
dpassage
4

Depois de experimentar tudo o que pude encontrar sobre o assunto, a única coisa que funcionou para mim foi, na verdade, executar o aplicativo, embora ainda exibisse o erro 'Nome do módulo-arquivo Swift.h não encontrado'.

Ele foi embora e meu aplicativo funciona perfeitamente bem. Acho que deveria ter pensado nisso antes ... O erro continua voltando , mas depois de executar o aplicativo, ele sempre desaparece novamente. Então, o problema não está realmente resolvido para mim, mas posso continuar trabalhando em outros tópicos por enquanto ...

Schrulnz
fonte
Sim, é uma solução para que o erro "não encontrado" desapareça.
Vijay Kumar Kanta
Mesmo agora, o Build falha enquanto apenas a execução do aplicativo funciona. Corrija isso, Apple!
ScottyB de
1

Um simples

@testable import MyProject

fez o trabalho para mim.

Niggeulimann
fonte
0

Estranhamente, eu estava vendo o mesmo erro, mas apenas ao direcionar um dispositivo (não o simulador). Antes de executar o teste, eu veria o ponto de exclamação vermelho próximo à instrução de importação para "MyProjectNameTests-Swift.h".

No entanto, o engraçado é que, se eu apenas prosseguir e executar o teste de qualquer maneira (apesar desse aparente erro de compilação), durante a fase de compilação que acontece depois disso, o XCode realmente gerará o arquivo "MyProjectNameTests-Swift.h" e o teste funciona muito bem!

Então, pelo menos no meu caso, não houve necessidade das outras soluções aqui, evidentemente, embora eu acredite que funcionem também.

Devo também observar que excluí meu diretório DerivedData antes disso, então talvez essa seja uma etapa que valha a pena tentar.

CommaToast
fonte
-1

mySwiftClassTests(e qualquer outra classe rápida que você deseja usar no objetivo-c) precisa ser marcada @objc:

@objc class MySwiftClassTests: XCTestCase
quem sabe
fonte
-1

Não consegui fazer funcionar adicionando aquele caminho de arquivo mencionado por outras respostas, mas percebi que o arquivo em que ele estava reclamando nem estava sendo testado. Eu apenas tive que removê-lo do alvo de teste usando a barra lateral direita de utilitários.

teradil
fonte
-2

Adicionar um arquivo .swift a esse destino corrige o problema nele.

Dmitry
fonte