测试是保障程序正确性的重要手段。功能上的漏洞不能直接被编译器检测和捕获,必须通过执行一些测试例并比较期望结果得出。手动编写测试用例是一个较为冗长繁琐的过程,Rust提供了一些自动化测试方法,能够标准化、高效化进行功能的自动测试。
Rust中的测试是一个测试函数,用于验证目标代码是否能够按照期望的方式运行,并输出期望结果。测试函数函数体一般包含三个部分:
Rust的测试函数是一个标注有test属性的函数。**属性(attribute)**元数据用于修饰Rust代码(derive也是)。只要标注test属性,命令行cargo test就会逐一调用所有的test函数,并生成报告。
创建library类型的工程,模板文件中自带单元测试样例:
pub fn add(left: usize, right: usize) -> usize {
left + right
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
let result = add(2, 2);
assert_eq!(result, 4);
}
}
assert族宏构成,每个assert宏都是一个测试样例
assert_eq,顾名思义,该宏将判断左右参数是否相等assert_ne,即不相等。还有最通用的assert,判断布尔表达式assert除了第一个表达式参数后,还可以有panic**宏的format string,以及后续参数。这些参数将被传递给panic,用于错误提示消息输出assert通过后,会输出一个测试通过的信息,并将通过数+1assert未通过,则输出错误信息(与普通panic相同),但仍会继续执行测试,并最终输出统计信息为了测试,另行编写一个测试函数如下:
#[test]
fn my_test() {
assert_eq!(2, 3);
}
运行cargo test,输出如下:
running 2 tests // progress
test tests::it_works ... ok
test my_test ... FAILED
failures: // part 1
---- my_test stdout ----
thread 'my_test' panicked at 'assertion failed: `(left == right)`
left: `2`,
right: `3`', src\lib.rs:7:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
failures: // part 2
my_test
// summary
test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
error: test failed, to rerun pass `--lib`
NativeCommandExitException: Program "cargo.exe" ended with non-zero exit code: 101.
输出主要由四部分构成(不包含Doc-tests,遇到测试失败):
可以在test属性的基础上,额外增加should_panic属性,用于检测对象是否按照预期的情况panic
当测试函数运行过程中发生panic,则通过测试,否则不通过。
#[test]
#[should_panic]
fn some_panic_test() {
...
}
另外,为should_panic属性增加expected参数,可以指定panic输出的消息
#[should_panic(expected="Some expected panic info")]
也可以使用Result编写测试,测试函数的返回值是Result<T, E>,当测试函数返回Err变体,就会被统计到测试失败中。
使用该方法可以在函数中调用?语法糖,编写测试程序更加方便。
默认情况下,cargo test生成的二进制文件会默认并行运行所有测试,并截获结果信息。
有关cargo test测试的更多参数,可以使用--help参数查看
test_threads指定并行测试的线程数
no-capture不截获正确测试例的标准输出
ignored 单独运行被忽略的测试
ignore属性,可以将这些函数排除在测试外,避免过于消耗资源的测试频繁运行单元测试只测试一小段代码的正确性。将项目分成一些小单元,分别对单元进行测试,能够大大降低整合测试的复杂度,优化排错效率。
单元测试模块通常放在每个源代码中,并以#[cfg(test)]标注,该标注使编译器只在运行cargo test时才编译运行该模块
单元测试仍然可以测试私有函数
继承测试完全位于代码库之外,通过调用库的接口完成测试,也就是只测试公开的那部分API功能。当然,部分功能也包含于这些API中。当然,集成测试也可能得到一些单元测试测不出来的bug,更加贴近于用户。
集成测试需要建立tests目录,cargo会自动寻找集成测试文件,并对每一个文件处理为独立的包。
在集成测试文件中,使用use引用被测目标,其他测试函数的编写方式与单元测试相同(可以不需要mod和#[cfg(test)])
如果想在集成测试中使用一些通用函数,可以将其放入tests/common/mod.rs中,这可以被rust识别,并且不会被编入普通测试
很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
我想用ruby编写一个小的命令行实用程序并将其作为gem分发。我知道安装后,Guard、Sass和Thor等某些gem可以从命令行自行运行。为了让gem像二进制文件一样可用,我需要在我的gemspec中指定什么。 最佳答案 Gem::Specification.newdo|s|...s.executable='name_of_executable'...endhttp://docs.rubygems.org/read/chapter/20 关于ruby-在Ruby中编写命令行实用程序
我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当
我有一个围绕一些对象的包装类,我想将这些对象用作散列中的键。包装对象和解包装对象应映射到相同的键。一个简单的例子是这样的:classAattr_reader:xdefinitialize(inner)@inner=innerenddefx;@inner.x;enddef==(other)@inner.x==other.xendenda=A.new(o)#oisjustanyobjectthatallowso.xb=A.new(o)h={a=>5}ph[a]#5ph[b]#nil,shouldbe5ph[o]#nil,shouldbe5我试过==、===、eq?并散列所有无济于事。
我有一些Ruby代码,如下所示:Something.createdo|x|x.foo=barend我想编写一个测试,它使用double代替block参数x,这样我就可以调用:x_double.should_receive(:foo).with("whatever").这可能吗? 最佳答案 specify'something'dox=doublex.should_receive(:foo=).with("whatever")Something.should_receive(:create).and_yield(x)#callthere
Sinatra新手;我正在运行一些rspec测试,但在日志中收到了一堆不需要的噪音。如何消除日志中过多的噪音?我仔细检查了环境是否设置为:test,这意味着记录器级别应设置为WARN而不是DEBUG。spec_helper:require"./app"require"sinatra"require"rspec"require"rack/test"require"database_cleaner"require"factory_girl"set:environment,:testFactoryGirl.definition_file_paths=%w{./factories./test/
我遵循MichaelHartl的“RubyonRails教程:学习Web开发”,并创建了检查用户名和电子邮件长度有效性的测试(名称最多50个字符,电子邮件最多255个字符)。test/helpers/application_helper_test.rb的内容是:require'test_helper'classApplicationHelperTest在运行bundleexecraketest时,所有测试都通过了,但我看到以下消息在最后被标记为错误:ERROR["test_full_title_helper",ApplicationHelperTest,1.820016791]test
我已经构建了一些serverspec代码来在多个主机上运行一组测试。问题是当任何测试失败时,测试会在当前主机停止。即使测试失败,我也希望它继续在所有主机上运行。Rakefile:namespace:specdotask:all=>hosts.map{|h|'spec:'+h.split('.')[0]}hosts.eachdo|host|begindesc"Runserverspecto#{host}"RSpec::Core::RakeTask.new(host)do|t|ENV['TARGET_HOST']=hostt.pattern="spec/cfengine3/*_spec.r
我在app/helpers/sessions_helper.rb中有一个帮助程序文件,其中包含一个方法my_preference,它返回当前登录用户的首选项。我想在集成测试中访问该方法。例如,这样我就可以在测试中使用getuser_path(my_preference)。在其他帖子中,我读到这可以通过在测试文件中包含requiresessions_helper来实现,但我仍然收到错误NameError:undefinedlocalvariableormethod'my_preference'.我做错了什么?require'test_helper'require'sessions_hel
我想在Ruby中创建一个用于开发目的的极其简单的Web服务器(不,不想使用现成的解决方案)。代码如下:#!/usr/bin/rubyrequire'socket'server=TCPServer.new('127.0.0.1',8080)whileconnection=server.acceptheaders=[]length=0whileline=connection.getsheaders想法是从命令行运行这个脚本,提供另一个脚本,它将在其标准输入上获取请求,并在其标准输出上返回完整的响应。到目前为止一切顺利,但事实证明这真的很脆弱,因为它在第二个请求上中断并出现错误:/usr/b