Tests unitaires: "Linker command failed with exit code 1"

Bonjour tout le monde!

Je suis occupé d’essayer d’ajouter des tests unitaires à mon application (oui je sais, c’est mal, je le fais un peu tard… :innocent:), mais j’ai un petit soucis :
Dès que j’essaye de lancer un test (simple), j’ai un beau « Build Failed » avec le message suivant:

Si cela peut vous aider, voici mon test:

if let personnes = Personne().getPersonnes() {
    XCTAssertEqual(personnes.count, 0)
}

Est-ce que vous savez m’expliquer à quoi est-ce dû ? Qu’est ce que je fais mal ?

Merci :slight_smile:

Hello, tu peux aller dans « Show the Report navigator » et ouvre le dernier Build que tu fais, ça devrait donner plus d’informations.

Bonjour @schtipoun, j’ai été regarder, mais je n’arrive pas à déchiffrer tout ce qu’il me dit…

Voici mon test (peut-être qu’il est mauvais, et que le soucis est là ?):

if let listePersonnes = Personne().getPersonnes() {
    XCTAssertEqual(0, listePersonnes.count)
}

Voici l’erreur :

Merci :slight_smile:

Tu travailles bien dans ton .xcworkspace et pas dans ton .xcodeproj ?
Parce que je vois que tu utilises Realm donc un pod donc qui dit pod dit .xcworkspace

Oui, je travaille bien directement dans le .xcworkspace, pour pouvoir utiliser REALM effectivement

Pour moi, l’erreur vient de Realm et on dirait que le pod a été mal compilé ou quelque chose du genre. Bref, il n’a pas l’air d’apprécier.
Tu as essayé de commenter toutes les lignes faisant appel à Realm et relancer le test ?
Ces lignes là ne doivent certainement pas être capitales dans ton test.

Dans ce cas-ci, REALM est important, puisque je souhaite vérifier après l’ajout d’une personne (par exemple), si la liste contient bien 1 personnes (et non plus 0), donc je récupère toutes les personnes dans la DB puis je les comptes (.count), donc si je commente la ligne, le test n’a plus d’utilité :confused:
Par contre, en effet, le soucis doit venir de REALM, puisque lorsque je fais une XCTAssert sans REALM, cela fonctionne… Mais je suppose qu’il est possible de faire fonctionner REALM avec des tests non ? :confused:

Ah bah oui c’est ça !
Je n’ai pas vu ta fonction en détail mais les tests unitaires sont là pour tester “en local”. Ex : je fais un getPersonnes(), alors mon compteur passe de 0 à 1

Mais pour ça, il faut que tu fasses quelque chose de ce genre :

let personnes = Personne() XCTAssertEqual(personnes.getPersonnesCount(), 0) _ = personnes.getPersonnes(for: "Alexandre") XCTAssertEqual(personnes.getPersonnesCount(), 1)

Les tests servent vraiment à valider le bon déroulement de ton app. Et ensuite, quand tu brancheras Realm, tout se passera comme dans tes tests :slight_smile:

J’ai un peu du mal à suivre:
ma fonction getPersonnes() me récupère toutes les personnes qui sont stockées dans ma DB, donc je ne peux pas faire getPersonnes(for: “Alexandre”) par exemple, et aussi, getPersonnesCount(), cette fonction retournerai le nombre de personnes en DB ? Mais je ne comprends pas pourquoi la faire, puisque je devrai également stocker cette information en DB, et que cette information est déjà disponible avec getPersonnes().count()…
Non? :confused:

Ah mais je ne sais pas comment tu as fait tes fonctions vu que je ne vois pas le reste de ton code.
Mais j’ai juste mis ça comme exemple (qui n’est pas forcément adapté à ton code). C’est juste pour te dire qu’il n’y a pas une seule ligne de Realm dedans !

Ok, donc si j’ai bien compris, je dois éviter REALM dans mes tests ?
Mais j’ai par contre du mal à voir, si j’évite REALM, comment je peux, par exemple, savoir, si lorsque j’ajoute une personne en DB, elle y est déjà, ou non ? Enfin, ou alors, je dois vraiment me concentrer sur des tests qui n’ont pas de rapport avec la DB, et donc REALM, mais alors j’ai du mal à imaginer les tests que je peux faire…
Merci pour ta patience et tes explications! :slight_smile:

Oui, il faut enlever Realm de tes tests et la DB et c’est même super important que, pendant tes tests, tu sois isolé des données de Realm.
Car, imagine tu exécutes ton premier tests, tu auras peut-être 2 personnes à la fin de ton test (parce que tu as exécuté 2 fois la fonction getPersonnes()). Et quand tu vas vouloir retester ton application, tu voudras vérifier que ton nombre de personnes soit à 0 (ce qui doit être vrai par rapport à la situation dans ton app) et ce ne sera pas le cas car tu auras déjà ajouté 2 personnes donc ton test sera forcément faux.
Il faut imaginer que le test fait sa propre DB en local et qu’il la régénère à chaque test pour éviter notamment qu’il y ait des soucis d’intégrité.

Pour t’isoler complètement de Realm, tu peux ajouter cette ligne de code au niveau de la fonction setUp()

    override func setUp() {
        super.setUp()
        // Put setup code here. This method is called before the invocation of each test method in the class.
        Realm.Configuration.defaultConfiguration.inMemoryIdentifier = self.name

Ça devrait résoudre ton problème.

1 « J'aime »

Oui, je suis tout à fait d’accord avec ton exemple, ça me parait effectivement logique! :slight_smile:

Je vais encore approfondir ces fameux tests, parce que du coup, j’ai du mal de voir comment vérifier certaines choses sans la DB…

Merci pour tes explications! :slight_smile:

1 « J'aime »

En fait, non, en effet, les tests unitaires doivent vraiment servir à tester une méthode dans un cas précis, pour voir les cas particulier par exemple, or, moi j’essayais de faire fonctionner pleins de choses à la fois, alors que justement non, je devrais plutôt tester cas par cas, et plutôt tester la logique de l’app dans les UITests! Je me trompe? :smiley:

Les tests et les UITests sont deux choses différentes.
Les tests te servent à t’assurer que la logique de ton application est bonne : j’ai 0 personnes au début puis quand j’en ajoute une, j’en ai 1 puis quand j’en ajoute une autre, j’en ai 2, etc.
Les UITests te servent à savoir si quand tu mets “Alexandre” dans le TextField, il y a bien Alexandre qui apparaît dans ton label. Ils servent vraiment à tester l’“apparence” (même si je n’aime pas trop ce mot là).

1 « J'aime »

Il s’agit d’un problème de Link (dernière étape de la compilation), ça veut dire qu’il n’a pas trouvé le code de Realm (plus exactement la propriété count de la classe Result) au moment de finaliser la compilation.
Dans ton Podfile tu dois avoir plusieurs targets (à moins que tu aies réglé Cocoapods avant d’ajouter la target de tests), il faut que Realm soit déclaré dans chacune des targets que où tu vas l’utiliser.
Ceci étant dit, je suis d’accord avec @schtipoun : Realm ne devrait pas être visible à l’extérieur de tes classes. Ca te permettra de pouvoir changer de type de sauvegarde sans avoir à changer tout ton programme si tu en as besoin.

1 « J'aime »