it-swarm.com.ru

Класс Foo реализован как в MyApp, так и в MyAppTestCase. Один из двух будет использован. Какой из них не определен

Недавно я начал модульное тестирование своего приложения. Этот проект (в Xcode4) был создан без комплекта модульных тестов, поэтому мне пришлось его настроить . Я выполнил следующие шаги: http://cocoawithlove.com/2009/12/sample-mac- application-with-complete.html И это работало хорошо для простых классов, но сейчас я пытаюсь протестировать класс, который зависит от другого, от другого и т. д.

Сначала я получил ошибку компоновщика, поэтому я добавил файлы *.m в цель теста, но теперь я получаю предупреждение для каждого класса, который пытаюсь проверить: 

Класс Foo реализован как в MyApp и MyAppTestCase. Один из двух будет использоваться. Какой из них не определен.

Интересно, почему это? Как я могу решить это? Может быть, я что-то упустил при установке цели юнит-теста?

Правка - решение

  • Установите «Bundle Loader» правильно на $(BUILT_PRODUCTS_DIR)/AppName.app/AppName

  • Установите «Символы, скрытые по умолчанию» на NO (в настройках сборки целевого приложения). Отсюда и ошибки компоновщика, потому что по умолчанию это YES !. Я так долго боролся с этим!.

Источник: Ошибка связывания для модульного тестирования с XCode 4?

60
nacho4d

Класс Foo реализован как в MyApp, так и в MyAppTestCase. Один из двух будет использован. Какой из них не определен.

Интересно, почему это?

потому что оба изображения (приложение и пакет модульного теста) определяют реализацию класса. класс динамически загружается в среду выполнения objc. среда выполнения objc использует плоское пространство имен. как это работает:

  • двоичный файл загружается, начиная с его зависимостей
  • при загрузке каждого двоичного файла классы objc регистрируются во время выполнения objc
  • если класс с определенным именем загружается дважды, поведение не определено. одна реализация класса (с одинаковыми именами) может быть загружена в среду выполнения objc.

типичная проблема здесь в том, что вам будет возвращена одна реализация - ваше приложение, скорее всего, будет аварийно завершать работу при конфликте типов (когда класс не происходит из одного и того же исходного файла).

вы обычно избегаете этого, переименовывая класс или экспортируя класс в одном изображении. переименование класса, очевидно, не относится к вашему делу. у вас есть один файл Foo.m, который компилируется, экспортируется и загружается двумя изображениями, когда он должен быть в одном.

это должно быть интерпретировано вами как ошибка компоновщика дубликатов символов. даже если реализация - это один и тот же исходный файл (и реализация одна и та же) - это проблема, которую вы должны решить.

Как я могу решить это?

если Foo.m является классом приложения, вы должны удалить (не компилировать и не ссылаться) Foo.m из модульного теста. если это часть модульного теста, не компилируйте и не связывайте его с целью модульного теста.

затем следуйте инструкциям в сообщении, чтобы связать/загрузить свой тестовый модуль в приложение. это в этой общей части поста: где «WhereIsMyMac» - это имя приложения, которое вы тестируете. Это позволит протестировать целевую ссылку на приложение (чтобы при компиляции не возникало ошибок компоновщика). важной частью является то, что ваши тестовые файлы скомпилированы в цели модульного теста (только), а классы вашего приложения скомпилированы и связаны с приложением. Вы не можете просто добавить их - они связываются и загружаются динамически.

Может быть, я что-то упустил при установке цели юнит-теста?

Из статьи вы связали:

Примечание. Цель тестирования - отдельная цель. Это означает, что вы должны быть осторожны с целевым членством. Все исходные файлы приложения должны быть добавлены только к цели приложения. Файлы тестового кода должны быть добавлены только к цели тестирования.

часть, которую вы ошиблись - это, вероятно, фазы соединения и загрузки пакета модульных тестов.

42
justin

Если вы используете Cocoapods, вашему подфайлу нужны только зависимости в разделе для основной цели, а не цели теста. Если вы добавите дубликаты зависимостей для целей тестирования, вы получите сообщение об ошибке OP.

target 'MyProject' do
pod 'Parse'

end

target 'MyProjectTests' do

end

target 'MyProjectUITests' do

end
15
Richard

Для меня все, что мне нужно было сделать, это снять флажок, который делает класс Foo членом цели модульного теста. Он не должен быть членом обеих целей и должен выглядеть так:

Target Membership

В случае, если вы не можете видеть изображение, это скриншот панели Xcode «Target Membership». Есть две цели: одна со значком приложения «А» и именем теста. Другой объект является модульным тестом и имеет значок модульного теста:

Target Membership
[X] Foo
[ ] FooTests
12
Steve HHH

Для меня это произошло потому, что я развернул на устройстве, а затем на симуляторе, так как у меня включены NSZombies. Решением было переключиться на конфигурацию симулятора и выполнить «Продукт» -> «Очистить», затем переключиться на конфигурацию устройства и сделать то же самое. Ошибка ушла. Это связано с кешем сборки.

3
Geoff H

Причина заключается в том, что вы переопределяете RUNPATH_SEARCH_PATHS настройки сборки вашей App Target, определенной в другой цели.

Решение:

Перейдите к своей цели приложения и найдите параметр сборки RUNPATH_SEARCH_PATHS и используйте там флаг $(inherited) для: Debug и Release

2
Bartłomiej Semańczyk

Встречайте одни и те же проблемы. Моя ситуация в том, что Class NSNotification реализован в обоих /System/Library/Frameworks/Foundation.framework/Foundation, есть ли какие-нибудь чуваки, сталкивающиеся с той же проблемой, любые указания или рекомендации будут оценены.

0
suxinde2009