objective-c - 在 Objective C 单元测试中模拟系统日期和位置的最佳实践

标签 objective-c cocoa-touch unit-testing mocking tdd

我正在尝试使用 TDD 方法在 Objective C 中编写一个类。 类应该基本上实现这个协议(protocol)。

@protocol SeasonService <NSObject>

-(t_Season)currentSeason;

@end

t_Season 只是冬季、 Spring 、夏季和秋季的枚举。

假设我有一个实现上面的类,下面是伪代码

@implementation SeasonServiceImpl

    - (t_Season)currentSeason
    {
        // Get Date
        int month = [self currentMonth];

        // Get Latitude
        float latitude = [self currentLatitude];

        // work out the season based on month and latitude 
        // (i.e, Northern or Southern hemisphere)
        return season;
    }
}

我可以通过使用类别暴露currentMonthcurrentLatitude方法来测试上面的公共(public)方法,然后使用OCMock进行部分模拟。这至少让我可以测试我的代码实现,以计算出基于日期和位置的季节。

但是

1) 对我来说,使用类别扩展有效地将两个私有(private)方法变成公共(public)方法似乎是一种代码味道。 2) 它没有测试我是否正确获取位置。

那么我该如何编码才能测试我是否正确获取了当前位置? 我的意思是,这里最好的方法是使用不同的指定 init 方法,该方法接受 CLLocationManager 的实例。这可能是模拟实例,也可能是代码在生产环境中运行时的真实实例? 另外,是否应该将 currentSeason 方法更改为类似 currentSeasonForDate:NSDate 的方法?

最佳答案

这类问题的传统解决方案是Dependency Injection ,这有助于驱动 Separation of Concerns . SeasonService 的工作是根据纬度和月份确定现在是什么季节。确定/存储纬度和月份应该是其他类的责任。

根据您的系统要求,这可以通过构造参数或方法参数来实现。无论哪种方式,您都可以直接模拟特定的月份或纬度,而不是诉诸类别技巧。

构造函数注入(inject):

- initWithLatitudeProvider:id<LatitudeProvider> latitudeProvider
          andMonthProvider:id<MonthProvider> monthProvider { 
    // set ivars or properties
}

- (t_Season)currentSeason
{
    // Get Date
    int month = [[self monthProvider] currentMonth];

    // Get Latitude
    float latitude = [[self latitudeProvider] currentLatitude];

    // work out the season based on month and latitude 
    // (i.e, Northern or Southern hemisphere)
    return season;
}

或者方法参数注入(inject):

- (t_Season)currentSeasonAtLatitude:(float)latitude inMonth:(int)month
{
    // work out the season based on month and latitude 
    // (i.e, Northern or Southern hemisphere)
    return season;
}

关于objective-c - 在 Objective C 单元测试中模拟系统日期和位置的最佳实践,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17376157/

相关文章:

ios - 像苹果的 iPad 邮件应用一样构建一个 "grouping"的动画

cocoa-touch - 在哪里可以获得更好的 Apple 文档?

iOS 应用程序 Facebook 集成 - iOS 5.0 的回退

objective-c - 如何使用 NSPredicate 基于子元素进行过滤?

iphone - 在iPad中实现像xcode的 "build success"这样的通知 View

javascript - ReferenceError : function is not defined. 在 Jasmine 单元测试中

Android 多线程单元测试

c# - Asp.Net Core 2.1 ApiController 不会自动验证单元测试下的模型

objective-c - 无法将数据发送到 VIPER 中的另一个模块

objective-c - Objective-C : How to support deprecated methods