2

ドキュメントとこの SO 投稿で示されているようにパッチャーを実装しようとしています: Typhoon: How to get an instance conforming to a protocol for production, and another for tests? .

ブロック アセンブリを使用していますが、次のエラーが表示されます。

[WPAnalyticsClientImplementation key]: unrecognized selector sent to instance 0x9eb01d0

TyphoonPatcher.m: 46

私のクラスの実装は、このセレクターに応答しません。それはすべきですか?キーはパッチ適用プロセスにどのように関連していますか?

context(@"when the controller does something", ^{

        it(@"should work", ^{
            // This is an application test, so the factory has already been set in the app delegate.
            TyphoonComponentFactory *factory = [TyphoonComponentFactory defaultFactory];

            TyphoonPatcher* patcher = [[TyphoonPatcher alloc] init];
            [patcher patchDefinition:[factory componentForType:@protocol(WPAnalyticsClient)] withObject:^id
             {
                 id mockAnalytics = [KWMock mockForProtocol:@protocol(WPAnalyticsClient)];
                 [[mockAnalytics should] conformToProtocol:@protocol(WPAnalyticsClient)];
                 [mockAnalytics stub:@selector(getSomeString) andReturn:theValue(@"fake implementation")];

                 return mockAnalytics;
             }];

            [factory attachPostProcessor:patcher];

            // The default factory should now return the mocked client.
            id <WPAnalyticsClient> client = [factory componentForType:@protocol(WPAnalyticsClient)];

            NSLog(@"conforms: %i", [client conformsToProtocol:@protocol(WPAnalyticsClient)]);
            NSString *actualValue = [client getSomeString];
            NSLog(@"someString: %@", actualValue);
            [[theValue([actualValue isEqualToString:@"fake implementation"]) should] equal:theValue(YES)];
        });
    });

AppDelegate.m

TyphoonComponentFactory *factory = ([[TyphoonBlockComponentFactory alloc] initWithAssembly:[WPAssembly assembly]]);
[factory makeDefault];
4

1 に答える 1

3

上記のパッチ コードは、インスタンスにパッチを適用するのではなく、定義にパッチを適用するのではなく、まったく正しくありません。

パッチャーが機能する方法は、TyphoonComponentFactoryPostProcessor を使用して定義を変更することです。

したがって、これを行うのではなく:

[patcher patchDefinition:[factory componentForType:@protocol(WPAnalyticsClient)] 
    withObject:^id. . .

これを行う必要があります:

MyAssemblyType* assembly = [MyAssemblyType assembly];
TyphoonComponentFactory* factory = [TyphoonBlockComponentFactory factoryWithAssembly:assembly];   
[patcher patchDefinition:[assembly myComponentToPatch] withObject . . . ]; 

デフォルト アセンブリにパッチを適用する::

新しいアセンブリを作成するのではなく、既定のアセンブリにパッチを適用しているため、次のように定義を渡す必要があります。

[patcher patchDefinition:[[MyAssemblyType assembly] myAnalticsService] withObject. . . ]

コンポーネント キーとアセンブリ インターフェイス

次のようなコンポーネントがあるとします。

- (id) myAnalyticsService 
{
    return [TyphoonDefinitionWithClass. . . . etc]; 
}

. . . コンポーネントのキーは@"myAnalyticsService"なので、以下も使用できます。

[patcher patchDefinitionWithKey:@"myAnalyticsService" . . ];

ビルド時と実行時のアセンブリ インターフェイス

混乱を招く可能性のある概念を次に示します。

アセンブリ インターフェイスには 2 つの目的があります。ビルド時には TyphoonDefinition を返し、実行時には定義で定義された実際の型を返します。そう 。.

  • ビルド時にコンポーネントを定義できます。

  • 実行時に、アセンブリ インターフェイスのメソッド名を使用してコンポーネントを解決できます。

例:

MyAssemblyType* assembly = (MyAssemblyType*) [TyphoonComponentFactory defaultFactory];
//Use the assembly interface instead of a 'magic string'
AnalyticsService* service = [assembly analyticsService]; 

これは多くの情報です。. . まだ不明な点がある場合はお知らせください。

于 2013-12-02T00:08:55.630 に答える