【问题标题】:Dependency injection for testing a class用于测试类的依赖注入
【发布时间】:2018-12-27 08:57:07
【问题描述】:

我想为单例类编写测试MySingleton

MySingletone.h:

@interface MySingleton : NSObject

@property (class, readonly, strong) Class_B* shared;

@end

MySingleton.m:

@interface MySingleton()
{
    SomeClass* _someClass;
}

@end

@implementation MySingletone

+ (MySingleton*)shared {
    static MySingleton* mySingleton;
    static dispatch_once_t predicate;

    dispatch_once(&predicate, ^{
        SomeClass* someClass = [[SomeClass alloc] init];
        mySingleton = [[MySingleton alloc] initWithSomeClass:someClass];
    });

    return mySingleton;
}

- (instancetype)initWithSomeClass:(SomeClass*)someClass {
    self = [super init];
    if (self) {
        _someClass = someClass;
    }
    return self;
}

@end

在测试中,我希望能够将具体的SomeClass 替换为假的,因此我定义了SomeClass 应符合的协议:

@protocol SomeProtocol
@end

@interface SomeClass : NSObject <SomeProtocol>
@end

@interface MySingleton : NSObject
{
  id<SomeProtocol> _someClass;
}
@property (class, readonly, strong)MySingleton* shared;

- (instancetype)initWithSomeClass:(id<SomeProtocol>)someClass;
@end

@implementation MySingleton

+ (MySingleton*)shared {

  static MySingleton* mySingleton;
  static dispatch_once_t predicate;

  dispatch_once(&predicate, ^{
    SomeClass* someClass = [[SomeClass alloc] init];
    mySingleton = [[MySingleton alloc] initWithSomeClass:someClass];
  });

  return mySingleton;
}

- (instancetype)initWithSomeClass:(id<SomeProtocol>)someClass {
  self = [super init];
  if (self) {
    _someClass = someClass;
  }
  return self;
}
@end

现在在我的测试中我定义了一个假类:

@interface someClassFake : NSObject <SomeProtocol>
@end

并用它初始化MySingleton

SomeClassFake* someFakeClass = [[SomeClassFake alloc] init];
MySingletone* mySingleton = [[MySingleton alloc] initWithObject: someClassFake];

我留下的唯一问题是在测试服中,虽然我没有使用具体的SomeClass,但我仍然依赖它,因为它在shared getter 中使用,链接器会问我为其提供实现。什么是最好的设计解决方案,这样我的测试服就不会依赖于SomeClass

【问题讨论】:

    标签: objective-c unit-testing testing dependency-injection dependencies


    【解决方案1】:

    我想出的最佳解决方案是将shared getter 移动到一个类别:

    MySingletone+Shared.h:

    @interface MySingleton (Shared)
    @property (class, readonly, strong)MySingleton* shared;
    @end
    

    MySMySingletone+Shared.m:

    @implementation MySingleton (Shared)
    
    + (MySingleton*)shared {
    
      static MySingleton* mySingleton;
      static dispatch_once_t predicate;
    
      dispatch_once(&predicate, ^{
        SomeClass* someClass = [[SomeClass alloc] init];
        mySingleton = [[MySingleton alloc] initWithSomeClass:someClass];
      });
    
      return mySingleton;
    }
    @end
    

    现在,在真正的代码中导入 MySingletone+Shared.h 而不是 MySingletone.h

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-01-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多