版本记录
版本号 | 时间 |
---|---|
V1.0 | 2019.01.01 星期二 |
前言
在这个信息爆炸的年代,特别是一些敏感的行业,比如金融业和银行卡相关等等,这都对
app
的安全机制有更高的需求,很多大公司都有安全 部门,用于检测自己产品的安全性,但是及时是这样,安全问题仍然被不断曝出,接下来几篇我们主要说一下app
的安全机制。感兴趣的看我上面几篇。
1. APP安全机制(一)—— 几种和安全性有关的情况
2. APP安全机制(二)—— 使用Reveal查看任意APP的UI
3. APP安全机制(三)—— Base64加密
4. APP安全机制(四)—— MD5加密
5. APP安全机制(五)—— 对称加密
6. APP安全机制(六)—— 非对称加密
7. APP安全机制(七)—— SHA加密
8. APP安全机制(八)—— 偏好设置的加密存储
9. APP安全机制(九)—— 基本iOS安全之钥匙链和哈希(一)
10. APP安全机制(十)—— 基本iOS安全之钥匙链和哈希(二)
11. APP安全机制(十一)—— 密码工具:提高用户安全性和体验(一)
12. APP安全机制(十二)—— 密码工具:提高用户安全性和体验(二)
13. APP安全机制(十三)—— 密码工具:提高用户安全性和体验(三)
14. APP安全机制(十四) —— Keychain Services API使用简单示例(一)
Testing the Behavior
在本节中,您将了解如何为包装器集成单元测试。 特别是,您将测试包装器公开的功能。
1. Creating the Class
要创建包含所有单元测试的类,请单击File ▸ New ▸ File…
并选择iOS ▸ Source ▸ Unit Test Case Class
。 在下一个屏幕上,将类名指定为SecureStoreTests
,子类XCTestCase
并确保语言为Swift
。 单击Next
,选择SecureStoreTests
组,验证是否已选中SecureStoreTests
目标复选框,然后单击Create
。
Xcode将提示一个对话框来创建一个Objective-C
桥接头。 单击Don’t Create
以跳过创建。
打开SecureStoreTests.swift
文件并删除花括号内的所有代码。
接下来,在import XCTest
语句下面添加以下内容:
@testable import SecureStore
这使单元测试访问SecureStore
框架中定义的类和方法。
注意:您可能会看到
“No such module”
错误。 不用担心,当您到本教程的这一部分结束并执行测试时,错误将消失。
接下来,在SecureStoreTests
的顶部添加以下属性:
var secureStoreWithGenericPwd: SecureStore!
var secureStoreWithInternetPwd: SecureStore!
接下来,添加一个新的setUp()
方法,如下所示:
override func setUp() {
super.setUp()
let genericPwdQueryable =
GenericPasswordQueryable(service: "someService")
secureStoreWithGenericPwd =
SecureStore(secureStoreQueryable: genericPwdQueryable)
let internetPwdQueryable =
InternetPasswordQueryable(server: "someServer",
port: 8080,
path: "somePath",
securityDomain: "someDomain",
internetProtocol: .https,
internetAuthenticationType: .httpBasic)
secureStoreWithInternetPwd =
SecureStore(secureStoreQueryable: internetPwdQueryable)
}
由于您测试了通用密码和Internet密码,因此您可以使用两种不同的配置创建包装器的两个实例。 这些配置是您在上一节中开发的配置。
在您忘记之前,您需要在测试的拆卸阶段清除钥匙串的状态,以便下次可以重新开始。 将此方法添加到类的末尾:
override func tearDown() {
try? secureStoreWithGenericPwd.removeAllValues()
try? secureStoreWithInternetPwd.removeAllValues()
super.tearDown()
}
由于您应该独立于其他测试隔离和执行每个测试,因此您将删除Keychain
中已有的所有密码。 执行顺序无关紧要。
现在是时候为通用密码添加单元测试了。
2. Testing Generic Passwords
在tearDown()
下面添加下面代码
// 1
func testSaveGenericPassword() {
do {
try secureStoreWithGenericPwd.setValue("pwd_1234", for: "genericPassword")
} catch (let e) {
XCTFail("Saving generic password failed with \(e.localizedDescription).")
}
}
// 2
func testReadGenericPassword() {
do {
try secureStoreWithGenericPwd.setValue("pwd_1234", for: "genericPassword")
let password = try secureStoreWithGenericPwd.getValue(for: "genericPassword")
XCTAssertEqual("pwd_1234", password)
} catch (let e) {
XCTFail("Reading generic password failed with \(e.localizedDescription).")
}
}
// 3
func testUpdateGenericPassword() {
do {
try secureStoreWithGenericPwd.setValue("pwd_1234", for: "genericPassword")
try secureStoreWithGenericPwd.setValue("pwd_1235", for: "genericPassword")
let password = try secureStoreWithGenericPwd.getValue(for: "genericPassword")
XCTAssertEqual("pwd_1235", password)
} catch (let e) {
XCTFail("Updating generic password failed with \(e.localizedDescription).")
}
}
// 4
func testRemoveGenericPassword() {
do {
try secureStoreWithGenericPwd.setValue("pwd_1234", for: "genericPassword")
try secureStoreWithGenericPwd.removeValue(for: "genericPassword")
XCTAssertNil(try secureStoreWithGenericPwd.getValue(for: "genericPassword"))
} catch (let e) {
XCTFail("Saving generic password failed with \(e.localizedDescription).")
}
}
// 5
func testRemoveAllGenericPasswords() {
do {
try secureStoreWithGenericPwd.setValue("pwd_1234", for: "genericPassword")
try secureStoreWithGenericPwd.setValue("pwd_1235", for: "genericPassword2")
try secureStoreWithGenericPwd.removeAllValues()
XCTAssertNil(try secureStoreWithGenericPwd.getValue(for: "genericPassword"))
XCTAssertNil(try secureStoreWithGenericPwd.getValue(for: "genericPassword2"))
} catch (let e) {
XCTFail("Removing generic passwords failed with \(e.localizedDescription).")
}
}
这里有很多东西,所以要把它分解:
- 1)
testSaveGenericPassword()
方法验证它是否可以正确保存密码。 - 2)
testReadGenericPassword()
首先保存密码然后检索密码,检查密码是否等于预期的密码。 - 3)
testUpdateGenericPassword()
验证为同一帐户保存不同的密码时,最新的密码是检索后的预期密码。 - 4)
testRemoveGenericPassword()
测试它可以删除特定帐户的密码。 - 5) 最后,
testRemoveAllGenericPasswords
检查是否从Keychain
中删除了与特定服务相关的所有密码。
由于您的包装器可以抛出异常,因此每个catch块会在出现问题时使测试失败。
3. Checking Your Work
现在是时候验证一切都按预期工作了。 选择TestHost
作为Xcode项目的活动scheme
:
按键盘上的Command-U
(或选择Product ▸ Test
中的测试)以执行单元测试。
注意:您不需要像通常在教程中那样运行应用程序。 在本教程中,您将通过执行单元测试来检查代码。
显示测试导航器并等待测试执行。 一旦完成,你会发现所有五个测试都是绿色的。太好了!
接下来,对互联网密码执行相同操作。
滚动到类的末尾,在最后一个花括号之前添加以下内容:
func testSaveInternetPassword() {
do {
try secureStoreWithInternetPwd.setValue("pwd_1234", for: "internetPassword")
} catch (let e) {
XCTFail("Saving Internet password failed with \(e.localizedDescription).")
}
}
func testReadInternetPassword() {
do {
try secureStoreWithInternetPwd.setValue("pwd_1234", for: "internetPassword")
let password = try secureStoreWithInternetPwd.getValue(for: "internetPassword")
XCTAssertEqual("pwd_1234", password)
} catch (let e) {
XCTFail("Reading internet password failed with \(e.localizedDescription).")
}
}
func testUpdateInternetPassword() {
do {
try secureStoreWithInternetPwd.setValue("pwd_1234", for: "internetPassword")
try secureStoreWithInternetPwd.setValue("pwd_1235", for: "internetPassword")
let password = try secureStoreWithInternetPwd.getValue(for: "internetPassword")
XCTAssertEqual("pwd_1235", password)
} catch (let e) {
XCTFail("Updating internet password failed with \(e.localizedDescription).")
}
}
func testRemoveInternetPassword() {
do {
try secureStoreWithInternetPwd.setValue("pwd_1234", for: "internetPassword")
try secureStoreWithInternetPwd.removeValue(for: "internetPassword")
XCTAssertNil(try secureStoreWithInternetPwd.getValue(for: "internetPassword"))
} catch (let e) {
XCTFail("Removing internet password failed with \(e.localizedDescription).")
}
}
func testRemoveAllInternetPasswords() {
do {
try secureStoreWithInternetPwd.setValue("pwd_1234", for: "internetPassword")
try secureStoreWithInternetPwd.setValue("pwd_1235", for: "internetPassword2")
try secureStoreWithInternetPwd.removeAllValues()
XCTAssertNil(try secureStoreWithInternetPwd.getValue(for: "internetPassword"))
XCTAssertNil(try secureStoreWithInternetPwd.getValue(for: "internetPassword2"))
} catch (let e) {
XCTFail("Removing internet passwords failed with \(e.localizedDescription).")
}
}
请注意,上面的代码与之前分析的代码相同。 您刚刚使用secureStoreWithInternetPwd
替换了引用secureStoreWithGenericPwd
。
选择TestHost
作为活动scheme
(如果尚未选择),然后按键盘上的Command-U
再次进行测试。 现在所有的通用和互联网密码测试都应该是绿色的。
恭喜! 您现在有一个可用的独立框架和单元测试。
后记
本篇主要讲述了Keychain Services API使用简单示例,感兴趣的给个赞或者关注~~~