iosios 单元测试框架有哪些

1.什么是单元测试?
答:单元测试是苹果为了方便我们进行某一模块业务的检测而推出的测试环境!所谓测试环境就是另一个我们写代码的地方。它存在于我们项目不同的文件夹下面。
2.怎么使用单元测试?
答:可以直接在系统写好的test.m中写测试代码,当然也可以自己新建一个测试文件。
当然你也可以自己新建一个单元测试类!
XCTAssert 是一个断言 可以利用这个断言进行测试
当测试通过以后在点击的那个小圈圈里面会有个绿色的对勾标志证明单元测试通过
如果出现红色的X 说明单元测试失败
3.那为什么使用这个单元测试呢?它给我们带来了什么好处呢?
答:通常一般我们为了省事 通常会直接在工程中写一些测试代码 如NSLog一些打印测试 断言 等等,但是 如果测试代码过多会是工程变得看起来很乱,而且工程体积也会变的大一些,当我们测试完成以后还要将以前写的测试代码删掉,难道不觉得我们辛辛苦苦写的测试代码 再我们不需要时候再删掉 或者说如果我们再次需要这个测试的时候 再一次来写 这种反复操作很烦嘛? 当然单元测试很好的解决了这一切。 因为测试单元中的代码 不会打包到我们的工程里面,而且它也不会build整个工程只会run 你所写的那个方法 省时 省力!空说 可能无法理解它的好处,用起来就知道了。
阅读(...) 评论()iOS开发实战:如何在ReactiveCocoa中编写单元测试?
发表于 15:20|
作者刘耀柱
摘要:在开发iOS应用时使用ReactiveCocoa的开发者可谓多数,但很多时候使用它之后,如何编写单元测试来验证程序是否正确呢?本文作者通过一个例子来讲述自己是如何在RAC中使用Kiwi来编写单元测试。
CSDN移动将持续为您优选移动开发的精华内容,共同探讨移动开发的技术热点话题,涵盖移动应用、开发工具、移动游戏及引擎、智能硬件、物联网等方方面面。如果您想投稿、参与内容翻译工作,或寻求近匠报道,请发送邮件至tangxy#csdn.net(请把#改成@)。&
现在很多人在开发iOS时都使用,它是一个函数式和响应式编程的框架,使用Signal来代替KVO、Notification、Delegate和Target-Action等传递消息和解决对象之间状态与状态的依赖过多问题。但很多时候使用它之后,如何编写来验证程序是否正确呢?下面首先了解MVVM架构,然后通过一个来讲述我如何在RAC(ReactiveCocoa简称)中使用来编写单元测试。
在MVVM架构中,通常都将view和view controller看做一个整体。相对于之前MVC架构中view controller执行很多在view和model之间数据映射和交互的工作,现在将它交给view
model去做。
至于选择哪种机制来更新view model或view是没有强制的,但通常我们都选择。ReactiveCocoa会监听model的改变然后将这些改变映射到view
model的属性中,并且可以执行一些业务逻辑。
举个例子来说,有一个model包含一个dateAdded的属性,我想监听它的变化然后更新view model的dateAdded属性。但model的dateAdded属性的数据类型是NSDate,而view
model的数据类型是NSString,所以在view model的init方法中进行数据绑定,但需要数据类型转换。示例代码如下:
RAC(self,dateAdded) = [RACObserve(self.model,dateAdded) map:^(NSDate*date){
return [[ViewModel dateFormatter] stringFromDate:date];
}];ViewModel调用dateFormatter进行数据转换,且方法dateFormatter可以复用到其他地方。然后view controller监听view
model的dateAdded属性且绑定到label的text属性。
RAC(self.label,text) = RACObserve(self.viewModel,dateAdded);
现在我们抽象出日期转换到字符串的逻辑到view model,使得代码可以测试和复用,并且帮view controller瘦身。
如图所示,这是一个简单的登录界面:有用户名和密码的两个输入框,一个登录按钮。用户输入完用户名和密码后,点击登录按钮后,成功登录。但这里有限制条件:用户名必须满足邮件的格式和密码长度必须在6位以上。当同时满足这两个条件后才能点击按钮,否则按钮是不可点击的。大家可以从中下载实例代码。
首先我们先画界面,我定义一个LoginView,将画登录界面的责任都交给它。然后在LoginViewController中的viewDidLoad方法调用buildViewHierarchy加载它。
#pragma mark - Lifecycle
- (void)viewDidLoad {
[super viewDidLoad];
// build view hierarchy
[self buildViewHierarchy];
// bind data
[self bindData];
// handle events
[self handleEvents];
- (void)buildViewHierarchy
[self.view addSubview:self.rootView];
[self.rootView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(self.view);
}接下来我们要思考UI如何交互和如何设计和实现哪些类来处理。由于用户名和密码要同时满足验证格式时才能点击登录按钮,所以需要时刻监听usernameTextField和passwordTextField的text属性,对于处理UI交互、数据校验以及转换都交给MVVM架构中ViewModel来处理。于是定义一个LoginViewModel,并继承RVMViewModel,这个RVMViewModel有个active属性来表示viewModel是否处于活跃状态,当active是YES时,更新或显示UI。当active是NO时,不更新或隐藏UI。
@interface LoginViewModel : RVMViewModel
#pragma mark - UI state
@brief 用户名
@property (copy, nonatomic) NSString *
@brief 密码
@property (copy, nonatomic) NSString *
#pragma mark - Handle events
@brief 处理用户民和密码是否有效才能点击按钮以及登陆事件
@property (nonatomic, strong) RACCommand *loginC
#pragma mark - Methods
- (RACSignal *)isValidUsernameAndPasswordS
@end上面还有一个loginCommand属性和isValidUsernameAndPasswordSignal方法等下会详细介绍。定义LoginViewModel类后,在LoginViewController以组合和委托的方式来使用LoginViewModel并使用Lazy
Initialization来初始化它。
@interface LoginViewController ()
#pragma mark - View model
@property (strong, nonatomic) LoginViewModel *loginViewM
@implementation LoginViewController
#pragma mark - Custom Accessors
- (LoginViewModel *)loginViewModel
if (!_loginViewModel) {
_loginViewModel = [LoginViewModel new];
return _loginViewM
}最后调用bindData方法进行:
- (void)bindData
RAC(self.loginViewModel, username) = self.rootView.usernameTextField.rac_textS
RAC(self.loginViewModel, password) = self.rootView.passwordTextField.rac_textS
数据绑定测试
如果usernameTextField.text、passwordTextField.text与loginViewModel.username、loginViewModel.password已经绑定数据,那么usernameTextField.text和passwordTextField.text的数据变动的话,一定会引起loginViewModel.username和loginViewModel.password的改变。那么测试用例可以这样设计:
图:数据绑定Test Case
用kiwi编写测试如下:
SPEC_BEGIN(LoginViewControllerSpec)
describe(@"LoginViewController", ^{
__block LoginViewController *controller =
beforeEach(^{
controller = [LoginViewController new];
[controller view];
afterEach(^{
controller =
describe(@"Root View", ^{
__block LoginView *rootView =
beforeEach(^{
rootView = controller.rootV
context(@"when view did load", ^{
it(@"should bind data", ^{
rootView.usernameTextField.text = @"samlau";
rootView.passwordTextField.text = @"freedom";
[rootView.usernameTextField sendActionsForControlEvents:UIControlEventEditingChanged];
[rootView.passwordTextField sendActionsForControlEvents:UIControlEventEditingChanged];
[[controller.loginViewModel.username should] equal:rootView.usernameTextField.text];
[[controller.loginViewModel.password should] equal:rootView.passwordTextField.text];
SPEC_END这个测试中有两点需要重点解释:
初始化完controller之后,controller一定要调用view方法来加载controller的view,否则不会调用viewDidLoad方法。
如果有些朋友对controller如何管理view生命周期不了解,可以阅读文档中的章节。
图:Loading a view into memory from Apple Document
usernameTextField和passwordTextField一定要调用sendActionsForControlEvents方法来通知UI已经更新。
[rootView.usernameTextField sendActionsForControlEvents:UIControlEventEditingChanged];
[rootView.passwordTextField sendActionsForControlEvents:UIControlEventEditingChanged];一开始时,我并没有调用sendActionsForControlEvents方法导致loginViewModel.username和loginViewModel.password属性并没有更新。当时我开始思考,是不是还需要其他条件还能触发它更新呢?由于我使用UITextField的rac_textSignal属性,于是我就查看它的源代码:
- (RACSignal *)rac_textSignal {
@weakify(self);
return [[[[[RACSignal
@strongify(self);
return [RACSignal return:self];
concat:[self rac_signalForControlEvents:UIControlEventEditingChanged |
UIControlEventEditingDidBegin]]
map:^(UITextField *x) {
takeUntil:self.rac_willDeallocSignal]
setNameWithFormat:@"%@ -rac_textSignal", self.rac_description];
}从源代码可以知道,只有触发UIControlEventEditingChanged或UIControlEventEditingDidBegin事件时才能创建RACSignal对象。
推荐阅读相关主题:
CSDN官方微信
扫描二维码,向CSDN吐槽
微信号:CSDNnews
相关热门文章他的最新文章
他的热门文章
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)或微信扫描右侧二维码关注后
阅读原文和更多同类文章
如希望直接展示,可邮件联系我们(bang@aiweibang.com)iOS单元测试―OCMock常见使用方式_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
iOS单元测试―OCMock常见使用方式
阅读已结束,下载本文需要
想免费下载本文?
定制HR最喜欢的简历
你可能喜欢

我要回帖

更多关于 ios 单元测试覆盖率 的文章

 

随机推荐