作为一个Java开发者,你有很多个测试框架可选,这一节我将介绍传统的JUnit和TestNG,如果你没有接触过这些框架,你可以先看看他们的在线文档。使用JUnit你将给你之前的ToDo应用的存储类InMemoryToDoRepository.java编写单元测试,为了突出不同框架的相同和不同之处,所有的单元测试都会验证同一个类的功能。
如果你想构建可靠的高质量的软件,自动化测试将是你工具箱里面非常关键的一个部分,它帮助你减少手工测试的代价,提高你的开发小组重构已有代码的能力。自动化测试的类型 并非所有的自动化测试都是相似的,他们通常在作用域、实现方式和执行时间上有所差异,我把他们分成三种类型的测试:单元测试、集成测试和功能测试。
在之前的章节我们实现了一个简单但是功能齐全的web项目、学习了如何使用Gradle来构建和运行这个项目。测试代码是软件开发周期中非常重要的一环,能够确保软件的行为能符合预期。这一章我将讲述如何使用Gradle来组织、配置和执行测试代码,学习如何写单元测试、集成测试和功能测试并把他们集成到项目构建中。
每一个活跃的项目会随着时间慢慢增长的,一开始可能只是个很小的项目到后面可能包含很多包和类。为了提高可维护性和解藕的目的,你可能想把项目根据逻辑和功能来划分成一个个模块。模块通常按照等级来组织,相互之间可以定义依赖。Gradle给项目模块化提供了强大的支持,在Gradle中每个模块都是一个项目,我们称之为多项目构建,这一章介绍Gradle的多项目构建。
在第三章我们在构建To Do应用的时候学习到了怎么声明对Servlet ApI的依赖,Gradle的领域特定语言使得声明依赖和仓库变得很简单,你只需要在dependencies脚本中声明你所依赖的库,然后你需要告诉构建系统要从哪个仓库里下载依赖。提供了这两个信息,Gradle就能自动解析、下载依赖到你的电脑上,如果有需要会存储在本地缓存中必备以后需要。
每个Gradle构建都包括三个基本的构建块:项目(projects)、任务(tasks)和属性(properties),每个构建至少包括一个项目,项目包括一个或者多个任务,项目和任务都有很多个属性来控制构建过程。
在第三章,我们在Gradle核心插件的帮助下构建了一个Java Web项目,我们了解到这些插件都是可以自定义来适应自己的非标准化的构建需求、给你的项目添加可执行的构建逻辑来配置tasks。
你把你的Web应用给你的同伴Mike看,他看完之后觉得很有意思想加入你给项目添加一些高级特性。你把代码添加到版本控制系统当中(VCS),因此它可以下载代码,由于Mike从来没有用过Gradle构建工具,所以他问你用的哪个版本的Gradle以及怎么安装Gradle,他也不知道怎么去配置Gradle,从以往的经验来看,Mike清醒的知道不同版本的构建工具或者运行环境对对构建的影响有多大。
Gradle目前的版本是2.4,根据其Wiki上的Roadmap,Gradle有着让很多成熟项目都汗颜的文档,其包括了安装指南、基本教程、以及一份近300页的全面用户指南。这对于用户来说是非常友好的,同时也说明了Gradle的开发者对这个项目非常有信心,要知道编写并维护文档可不是件轻松的工作,对于Gradle这样未来仍可能发生很大变动的项目来说尤为如此。类似于Maven的pom.
通常情况下,一个简单的 if/else 是不足够的,因为你可能有两个以上的选择。此外,条件可能变得相当复杂。Rust 有关键字 match,允许你用更强大的 match 关键字,取代复杂的 if/else 集合。如下所示: let x = 5;match x {1 => println!("one"),2 => println!("two"),3 => println!("three"),4 => println!("four"),5 => println!("five"),_ =>
在 Rust 中枚举是一个类型,它表示几个可能变量中的一个数据: enum Message {Quit,ChangeColor(i32, i32, i32),Move { x: i32, y: i32 },Write(String),}每个变量可以选择性的有与之关联的数据。定义变量的语法与之前定义结构体的语法类似:你可以有不包含数据的变量(如 unit-like 结构体),已经命名数据的变量,和未命名数据的变量(如数据结构体)。
结构体是创建更复杂的数据类型的一种方式。例如,如果我们做涉及在二维空间中的坐标计算时,我们可能既需要 x 的值,也需要 y 的值: let origin_x = 0;let origin_y = 0;一个结构体让我们将二者结合成为一个单一的,统一的数据类型: struct Point {x: i32,y: i32,}fn main() {let origin = Point { x: 0, y: 0 }; // origin: Pointprintln!
可变性,可以改变东西的能力,与其他语言相比它在 Rust 中有点不同。可变性的第一个方面是它的非默认状态: let x = 5;x = 6; // error!我们可以应用 mut 关键字来介绍可变性:let mut x = 5;x = 6; // no problem!这是一个可变的变量绑定。当一个绑定是可变时,这意味着你可以更改绑定的指向。
这篇指南是 Rust 已经存在的三个所有权制度之一。这是 Rust 最独特和最令人信服的一个特点,Rust 开发人员应该相当熟悉。所有权即 Rust 如何实现其最大目标和内存安全。这里有几个不同的概念,每一个概念都有它自己的章节: 所有权,即正在读的这篇文章。 借用,和与它们相关的功能‘引用’ 生存期,借用的先进理念 这三篇文章相关且有序。
这篇指南是 Rust 已经存在的三个所有权制度之一。这是 Rust 最独特和最令人信服的一个特点,其中 Rust 开发人员应该相当熟悉。所有权即 Rust 如何实现其最大目标和内存安全。这里有几个不同的概念,每一个概念都有它自己的章节: 所有权,即正在读的这篇文章。 借用,和与它们相关的功能‘引用’ 生存期,借用的先进理念 这三篇文章相关且有序。
既然我们对函数有了一定了解之后,那么学习下如何写注释是不错的。注释的作用在于它能够帮助其他的程序员更好的理解你的代码。而编译期通常会忽视他们。Rust 中有两种你应该学习的注释方式:行注释和文档注释。// Line comments are anything after ‘//’ and extend to the end of the line.let x = 5; // this is also a line comment.
每个 Rust 程序至少包含一个函数,也就是 main 函数: fn main() { }这可能是最简单的函数声明。正如我们前面所提到的,fn 表明“这是一个函数”,紧随其后的是函数名字,一些括号,因为这个函数没有参数,然后一些花括号来表示函数体。这里有一个函数名称为 foo 的函数: fn foo() { }那么,函数的带参数是什么样的呢?
不管是人是鼠,即使最如意的安排设计,结局也往往会出其不意。《致老鼠》 罗伯特·彭斯有时候,事情会出乎意料的发生错误。重要的是要提前想好应对错误的方法。Rust 有丰富的支持错误处理方法来应对可能(老实说:将会)发生在您的程序中的错误。主要有两种类型的错误可能发生在你的程序中:故障和异常。让我们谈谈两者之间的区别,然后讨论如何处理它们。
并发性和并行性在计算机科学中是非常重要的主题,即使在当今工业中也是个热门的话题。电脑得到了越来越多的核心,然而,很多程序并没有能力来利用它们。Rust 内存安全特性同样采用了并发的方式。甚至 Rust 程序内存必须是安全,没有数据之间的竞争。Rust 的类型系统的任务就是给你强大的方式让程序能够在编译时并发执行。
下面我们来探讨一下循环问题。还记得 Rust 的 for 循环吗?下面有一个例子:for x in 0..10 { println!("{}", x);}现在你已经知道了更多的 Rust,我们可以详细谈谈它是如何工作的。范围 (0 . . 10) 是一个迭代器。我们可以使用 .next() 方法反复调用迭代器,它给出了事情的一个序列。如下所示:let mut range = 0..10;loop { match range.
关注时代Java