18

私の単体テストの1つが失敗していて、予期していなかった理由があります。の呼び出しisKindOfClassがNOを返しているようですが、デバッグしてステップスルーすると、そうなる理由はないようです。

コードは次のとおりです。

if ([self.detailItem isKindOfClass:[MovieInfo class]]) {
    [self configureViewForMovie];
}

私はコードをステップスルーし、次のことを行いました。

po self.detailItem

表示されるもの:

(id) $1 = 0x0ea8f390 <MovieInfo: 0xea8f390>

では、何が欠けているのでしょうか。この場合、ifステートメントがfalseを返すのはなぜですか。

編集:

DetailItemのセッターは次のとおりです。

- (void)setDetailItem:(id)newDetailItem
{
    if (_detailItem != newDetailItem) {
        NSLog(@"%@", [newDetailItem class]);
        _detailItem = newDetailItem;

        // Update the view.
        [self configureView];
    }

    if (self.masterPopoverController != nil) {
        [self.masterPopoverController dismissPopoverAnimated:YES];
    } 
}

これは、マスター詳細テンプレートのテンプレートコードです。

単体テストは、setUpにMovieInfoを作成します。

movie = [[MovieInfo alloc] initWithMovieName:@"Movie" movieID:1];

テストに設定します

controller.detailItem = movie;

さらに、次の場所にパラメータアサーションを追加しましたsetDetailItem

NSParameterAssert([newDetailItem isKindOfClass:[MovieInfo class]] || [newDetailItem isKindOfClass:[PersonInfo class]] || newDetailItem == nil);

このアサーションも失敗しています。

アサーション呼び出しの上に2つのログステートメントを配置しました。

NSLog(@"%@", [newDetailItem class]);
NSLog(@"%@", newDetailItem);

どの表示:

2012-08-28 08:31:37.574 Popcorn[8006:c07] MovieInfo
2012-08-28 08:31:38.253 Popcorn[8006:c07] <MovieInfo: 0x6daac50>

もう1つの編集:

isKindOfClassユニットテストで設定する前にチェックを追加しました。これは合格です。

if ([movie isKindOfClass:[MovieInfo class]]) {
    NSLog(@"Yep"); //This passes and prints out
}
controller.detailItem = movie; //calls into the setter and fails.
4

10 に答える 10

16

これは、テスト対象のクラス「DetailViewController」がテストのターゲットに含まれていなかったことが原因でした。私はこれが別の方法(リンカーエラーなど)で現れることを期待していましたが、どうやら、それは奇妙な振る舞いを引き起こすだけです。DetailViewControllerをテストターゲットに追加すると、問題が修正されました。

于 2012-08-28T14:13:43.680 に答える
2

競合状態、またはデバッグ構成とリリース構成の違いが疑われます。これらは、デバッガーと通常のランタイムの違いにつながります。

まず、そうでself.detailItemはないことを確認してくださいnil。これが、この種の問題の最も一般的な原因です。次に、デバッガーではなくロギングを使用してこれをデバッグしてみてください。本当に競合状態がある場合は、printf()ではなくを使用してログを記録することも検討してくださいNSLog()printf()マルチスレッドロギングを実行するためのパフォーマンスへの影響がはるかに少ない方法です。

于 2012-08-28T13:13:22.687 に答える
2

私が書いているライブラリでこれと同じ問題が発生しました。おかしなことに、iOSのテストターゲットでは問題なく動作しましたが、Macのテストターゲットでは失敗しました(興味深い!)。

この問題は、クラス宣言の不一致に関連していると思います。ライブラリは.h宣言を使用していますが、単体テストは内部宣言を調べていました。

例を使って説明する方が簡単です。

/*
 * ClassA.h
 */
@interface ClassA () : NSObject

@property (nonatomic, strong, readonly) NSString *someValue1;
@property (nonatomic, strong, readonly) NSString *someValue2;
@property (nonatomic, strong, readonly) NSString *someValue3;

@end

.mのプロパティリストに追加する

/*
 * ClassA.m
 */
@interface ClassA () : NSObject

@property (nonatomic, strong, readwrite) NSString *someValue2;
@property (nonatomic, strong, readwrite) NSDate *date;
@property (nonatomic, strong, readwrite) NSDateFormatter *dateFormatter;

@end

@implementation 
// implementation
@end

これで、単体テストターゲットのコンパイルソースがClassA.mを含むように設定されているため、はisKindOfClass:noを返しますが、poコマンドとNSStringFromClass([ClassA class])デバッガーで実行すると、期待する値が返されます。

これが古い投稿であることは知っていますが、これがお役に立てて、誰かの時間を大幅に節約できることを願っています。この問題を理解しようとして、ほぼ1時間かかりました。

于 2014-08-06T16:57:39.943 に答える
1

すべてのソースファイルをすべてのテストターゲットに常に追加したい場合、MarkPowellの答えは絶対に役立ちます。

ただし、テストターゲットのターゲット依存関係としてアプリケーションがある場合(プロジェクトソースファイルではなく、テストターゲットにテストソースファイルのみがある場合)、私が抱えていたのと同じ問題が発生します。クラスの1つが必要です。テストターゲットではなく、アプリターゲットに含まれている(私の場合はテストヘルパークラスでした!)

于 2014-09-04T13:04:43.970 に答える
1

@stefreakが述べたように、標準の単体テスト構成では、テスト対象のオブジェクトを単体テストのターゲットに含めないでください。この状況で、テスト対象のオブジェクトをテストターゲットに含めると、ビルド時に次のタイプのメッセージがログに書き込まれます。

Class foo is implemented in both <.app path> and <.xctest path>. One of the two will be used. Which one is undefined.

ここで述べたように、両方のターゲットにテスト対象のオブジェクトを含めないでください。オブジェクトを1つのターゲットにのみ含めると、。を使用して予期しない動作を停止できisKindOfClass:ます。

また、私の同僚は、「実行」ビルドの単体テストがオフになっていることを確認する必要があることを発見しました。アプリケーションのスキームで、[ビルド]を選択し、単体テストのターゲットを確認します。[実行]の選択を解除する必要があります。

Swiftで開発している場合は@testable import MyModule、単体テストファイルの先頭にが表示されているはずです。

于 2015-11-16T05:05:44.507 に答える
0

self.detailItemこれまでにできますnilか?その場合の結果はに-isKindOfClass:なりますNO

于 2012-08-28T13:24:44.020 に答える
0

同じ状況が私にも起こっています。私は次のように比較を行うことになりました:

[self.detailItem class]  == [ETTWallpaper class]

以来

[[self.detailItem class] isKindOfClass:[ETTWallpaper class]]

動作していなかったため、YESを返す必要があることを確認したにもかかわらず、常にNOを返しました。

于 2014-01-14T23:13:04.717 に答える
0

現在、Xcode7.0にはバグがあると思います。同じ問題があり、すべてのCUTがテストターゲットに含まれていることを確認しましたが、コードではに戻るNOもの-[isKindOfClass:]がありますが、デバッガーではYESを返します。そして、これはシミュレーターや物理デバイスで起こっています。

私は-[respondsToSelector:]クラスの署名をチェックするためにチェックすることになりました。完璧ではありませんが、私は通り抜けることができます。

于 2015-10-04T11:21:06.983 に答える
0

SomeClassCocoaPods 1.0(ポッドライブラリ内にある)で単体テストを実行するときに同じ問題が発生します

次の警告メッセージが表示されました。

Class SomeClass is implemented in both </path/to/myapp> and </path/to/myapptest>. One of the two will be used. Which one is undefined.

私の解決策は、Podfileを次のように更新することです。

target "MyApp" do
  pod 'xxx'
  pod 'yyy'

  target "MyApp-Tests" do
      inherit! :search_paths
  end
end

参照: https ://github.com/CocoaPods/CocoaPods/issues/4626

于 2017-02-15T07:34:23.707 に答える
0

このリンクで解決策を見つけました:

私のSomeEntityクラスはテストターゲットに含まれていました。テストターゲットの構築には、SomeEntityも含む依存関係としてメインアプリケーションも含まれます。それは明らかにXcodeに2つの異なるタイプがあると信じさせます。

テストターゲットからSomeEntityを削除すると、すべて合格です。

于 2019-07-25T20:14:26.763 に答える