zoukankan      html  css  js  c++  java
  • 定义你的数据模型

    在本课程中,您将定义和测试的应用程序FoodTracker数据模型。一个数据模型表示在APP中的的信息结构。

    学习目标

    在课程结束时,你将能够:

    1.创建数据模型
    2.写failable初始化一个自定义类
    3.证明failable和nonfailable的不同,理解他们之间的差异和概念
    4.通过编写和运行单元测试来测试数据模型

    创建一个数据模型

    现在你需要创建一个数据模型来存储菜谱场景所需要显示的信息。要做到这一点,我们需要定义个简单的类,里面有name,photo,rating

    创建一个新的数据模型类

    1.选择File > New > File (或按下Command+N)

    2在对话框左边,选择iOS下的Source

    3.选择Swift File,然后点击下一步

    和前面创建RatingControl 所不同,对于数据模型,我们不需要继承其他类

    4.在Save as旁,键入Meal

    5.默认保存位置是项目目录,Group默认选择为你的App 名字FoodTracker,在Target选择,确保app和tests都被选中

    6.点击Create。Xocde会创建一个名叫Meal.swift的文件

    在Swift中,你能使用一个String表示一个name,使用UIImage表示photo,使用Int表示rating。因为一个菜谱总是会有一个name和rating。但不一定会有图片。所以UIImage是可选的

    为菜谱定义数据模型

    1.打开Meal.swift

    2.修改导入语句为UIKit

    import UIKit

    默认1个Swift文件会导入为Foundation框架,它使你能够使用基础数据结构。你需要使用UIKit框架中的类,所以你需要导入UIKit,同时UIKit也能让你访问Foundation,因此你可以移除这个多余的Foundation语句

    3.然后添加如下代码:

    class Meal {
        // MARK: Properties
        
        var name: String
        var photo: UIImage?
        var rating: Int
    }

    代码定义了你需要存储的基础属性。你使用变量(var)而不是常量(let),因为他们在整个菜谱的生命周期中会发生改变

    4.在属性代码下方,添加如下初始化代码:

    // MARK: Initialization
     
    init(name: String, photo: UIImage?, rating: Int) {
    }

    回忆一个初始化方法,当一个类的实例准备初始化时,我们可以为每个属性设置一个初始化值,或执行一些设置和初始化操作

    5.通过参数值来给基础属性赋值

    // Initialize stored properties.
    self.name = name
    self.photo = photo
    self.rating = rating

    如果你尝试使用不正确的值来创建一个菜谱,会发生如一个空的name或负数的rating。你需要返回nil来表示item不能被创建,也不能设置为默认值。你需要添加代码来检查一些失败的情况

    6.在初始化结束的地方,加入if语句来检查无效值

    // Initialization should fail if there is no name or if the rating is negative.
    if name.isEmpty || rating < 0 {
        return nil
    }

    因为初始化函数中可能返回nil,所以你需要在初始化函数指出标识

    7.点击fix-it,在init关键字后面来添加(?)

    init?(name: String, photo: UIImage?, rating: Int) {

    这个初始化程序被称为failable initializer,它表示这个初始化程序可能会返回nil

    现在整体init函数,应该如下所示:

    // MARK: Initialization
     
    init?(name: String, photo: UIImage?, rating: Int) {
        // Initialize stored properties.
        self.name = name
        self.photo = photo
        self.rating = rating
        
        // Initialization should fail if there is no name or if the rating is negative.
        if name.isEmpty || rating < 0 {
            return nil
        }
    }

    测试你的数据

    虽然你的数据模型编译了,但你还没有完全将其纳入到你的APP中。因此,很难判断是否已正确实现一切,在运行时你可能会遇到,没有考虑的边缘情况。

    为了解决这种不确定性,你可以写单元测试,单元测试用于测试小的,独立的代码片段,以确保他们的行为正确。菜谱类正好是单元测试一个完美的候选人。Xcode已经帮你创建了一个单元测试文件

    查看FoodTracker中的单元测试中的文件

    1.打开FoodTrackerTests文件夹,通过点击三角形,展开里面的列表

    2.打开 FoodTrackerTests.swift

    花一点时间来了解文件中的代码

     

    import UIKit
    import XCTest
     
    class FoodTrackerTests: XCTestCase {
        
        override func setUp() {
            super.setUp()
            // Put setup code here. This method is called before the invocation of each test method in the class.
        }
        
        override func tearDown() {
            // Put teardown code here. This method is called after the invocation of each test method in the class.
            super.tearDown()
        }
        
        func testExample() {
            // This is an example of a functional test case.
            XCTAssert(true, "Pass")
        }
        
        func testPerformanceExample() {
            // This is an example of a performance test case.
            self.measureBlock() {
                // Put the code you want to measure the time of here.
            }
        }
        
    }

     

    我们导入的XCText框架,是Xcode的测试框架。单元测试会定义在FoodTrackerTests类中,它继承自XCTestCase,代码注释解释了setUp()tearDown() 方法

    你写的功能测试(用来检查一切产生的值是否符合你的预期)和性能测试(检查你代码的性能是不是符合你预期那样快)是主要的测试类型。因为你没有写任何耗性能的代码,所以这样你只要写功能测试即可。

    一般在我们的测试方法前,会加上text前缀,如我们先要测试init方法,会这么写testMealInitialization

    为菜谱对象的初始化函数编写单元测试

    1.在 FoodTrackerTests.swift中,删除测试模版

    import UIKit
    import XCTest
     
    class FoodTrackerTests: XCTestCase {
        
    }

    本例中,我们不使用任何模版代码

    2.在类中,添加如下方法

    // Tests to confirm that the Meal initializer returns when no name or a negative rating is provided.
    func testMealInitialization() {
    }

    添加注释是一个好习惯,可以帮助你或其他浏览你代码的人,看懂你这个方法的意思,是要做什么

    3.首先添加一个通过的测试用例。添加注释

    // Success case.
    let potentialItem = Meal(name: "Newest meal", photo: nil, rating: 5)
    XCTAssertNotNil(potentialItem)

    XCTAssertNotNil是测试Meal对象在初始化后不为nil,这意味这你提供的参数会在初始化程序中成功创建一个Meal对象。

    4.现在添加一个Meal失败的测试用例。添加如下代码:

    // Failure cases.
    let noName = Meal(name: "", photo: nil, rating: 0)
    XCTAssertNil(noName, "Empty name is invalid")

    XCTAssertNil断言这个对象是nil。本例中,意思是noName这个对象为nil,意味着它初始化失败。你期望这个初始化失败,因为这个名字是一个空字符串,你明确地针对初始程序测试。

    5.我们在添加一个测试失败的用例,但这次我们断言他会成功:

    let badRating = Meal(name: "Really bad rating", photo: nil, rating: -1)
    XCTAssertNotNil(badRating)

    你期望这个用例会失败,因为rating为负数

    您可以通过按下Command-U在运行单元测试。最后一个测试用例预期失败,因为你断言对象非nil,它实际上是nil。

    运行单元测试

    1.在FoodTrackerTests.swift中,找到testMealInitialization()单元测试

    2.在测试名称的左边,找到一个菱形

    3.将鼠标悬停在菱形上会出现一个小的运行按钮

    4.点击这个执行按钮来运行单元测试

    检查站:你的应用程序运行在你刚刚编写的单元测试上。前两个测试用例应该通过,最后应该失败。

    正如你所看到的,单元测试有助于捕获代码中的错误。如果你真的希望在最后一个测试中的对象是非nil,你会在测试过程中发现这个错误。(在这种情况下,是因为你故意写了一个失败的测试案例,你可以回头去解决你的测试案例)

    修复测试用例

    1.在FoodTrackerTests.swift中找到testMealInitialization()

    2.修改代码为

    XCTAssertNil(badRating, "Negative ratings are invalid, be positive")

    完整的方法看起来应该是这样:

    // Tests to confirm that the Meal initializer returns when no name or a negative rating is provided.
    func testMealInitialization() {
        // Success case.
        let potentialItem = Meal(name: "Newest meal", photo: nil, rating: 5)
        XCTAssertNotNil(potentialItem)
        
        // Failure cases.
        let noName = Meal(name: "", photo: nil, rating: 0)
        XCTAssertNil(noName, "Empty name is invalid")
        
        let badRating = Meal(name: "Really bad rating", photo: nil, rating: -1)
        XCTAssertNil(badRating, "Negative ratings are invalid, be positive")
    }

    检查站:运行你刚刚编写单元测试。所有的测试用例应该会通过。

     

     

  • 相关阅读:
    Maven------使用maven新建web项目出现问题 项目名称出现红色交叉
    Strut2------获取界面返回的session,application,parameter
    js之可迭代对象
    js字符串
    js之strict模式
    js系列之js简介
    python私有成员
    python之偏函数
    python之装饰器
    python之匿名函数
  • 原文地址:https://www.cnblogs.com/tianjian/p/4617454.html
Copyright © 2011-2022 走看看