작은 녹 시작 힌트 시리즈: 테스트 및 TDD
karma 또는 mocha와 같은 테스트 프레임워크가 Javascript로 알려져 있는 것과 같이 rspec에 익숙한 사람들을 위해 멋진 보너스를 제공하고 rspec 구문을 캔디로 사용하여 테스트 코드를 보다 표현적이고 읽기 쉽게 만드는 방법을 보여줍니다.
문제 진술
가장 먼저 해야 할 일, 도전 과제의 문제 설명은
In today's challenge, you are asked to replace every letter with its position in the alphabet for a given string where 'a' = 1, 'b'= 2, etc.
For example:
alphabet_position("The sunset sets at twelve o' clock.") should return 20 8 5 19 21 14 19 5 20 19 5 20 19 1 20 20 23 5 12 22 5 15 3 12 15 3 11 as a string.
첫 번째 테스트 먼저
cargo new
로 새 프로젝트를 시작하고 소스 파일을 준비합시다cargo new dev_challenge_47
cd dev_challenge_47 && mkdir -f tests
touch tests/alphabet_position_test.rs
이제 요구 사항을 코드로 변환하는 것으로 시작하겠습니다. 지금은
for a given string where 'a' = 1
// test/alphabet_position_test.rs
use dev_challenge_47::alphabet_position; // <-- we don't have this function yet
#[test] // <-- how to define a test in rust
fn it_should_replace_the_a_with_1() { // <-- we express the requirement as name
let replaced = alphabet_position("a");
assert_eq!(replaced, "1"); // <-- we assert that the both are equal
}
이 시점에서 코드는 컴파일되지 않을 것이므로 테스트에 실패하지만 프로젝트를 컴파일하는 최소한의 구현을 작성해 보겠습니다.
// src/lib.rs
pub fn alphabet_position(s: &str) -> String {
String::from("Hello")
}
그래서 우리는 미리 정의된 "Hello"문자열을 반환하기만 하면 됩니다.
지금 실행하면
cargo test
많은 출력을 얻을 수 있지만test it_should_ignore_non_characters ... FAILED
좋습니다. 첫 번째 테스트가 실패했습니다.
테스트 통과하자
코드를 변경하여 첫 번째 테스트를 수정해 보겠습니다. 우리는 '1'을 '1'로 바꾸는 매우 순진한 구현으로 이것을 할 수 있지만 그 단계는 건너뛰고 리팩토링으로 건너뛸 것입니다. ASCII 수학처럼 사용할 위치:
x - 'a' + 1
// src/lib.rs
pub fn alphabet_position(s: &str) -> String {
s.chars() // <-- get an iterator over all chars
.map(|x| -> u8 { x as u8 - 'a' as u8 + 1 }) // <-- substract the ascii value of 'a'
.map(|x| -> String { x.to_string() }) // <-- convert the char to a String
.collect::<Vec<String>>() // <-- collect a Vector of String
.join(" ") // <-- join the Strings by whitespace
}
배울점이 많네요..
.chars()
chars의 반복자를 반환합니다.map
ASCII 수학을 수행하는 클로저를 적용합니다. .map
문자를 문자열로 변환하는 클로저를 적용합니다. .collect
벡터에 대한 모든 항목을 수집합니다.join
모든 문자열을 하나로 결합합니다재실행
cargo test
후 우리는 작은 테스트가 이제 녹색임을 알 수 있습니다.다음 반복
이미 짐작하셨겠지만 이제 테스트로 돌아가서 다른 테스트를 작성합니다. 그것은 기본적으로 TDD의 주기입니다. 우리는 조금씩 모든 요구 사항에 도달할 수 있도록 많은 테스트와 코드를 작성합니다. 이번에는 여기에 이 테스트를 추가합니다.
// test/alphabet_position_test.rs
#[test]
fn it_should_replace_the_capital_a_with_1() {
let replaced = alphabet_position("A");
assert_eq!(replaced, "1");
}
참고: 저는 너무 게으르므로
cargo test
다시 실행하고 싶지 않습니다. 이것이 파일의 변경 사항을 감시하고 테스트를 자동으로 다시 실행하는 cargo watch -x check -x test
를 사용하는 이유입니다. 설치하려면 체크아웃the docs하십시오.이제 실패한 테스트를 다시 수정합시다.
// src/lib.rs
pub fn alphabet_position(s: &str) -> String {
s.to_lowercase() // <-- adding this line
.chars()
.map(|x| -> u8 { x as u8 - 'a' as u8 + 1 })
.map(|x| -> String { x.to_string() })
.collect::<Vec<String>>()
.join(" ")
}
이제 수학이 실패하지 않도록 모두 소문자로 처리합니다.
또 다른 반복
ok 전체 문장을 보기 전에 모서리 케이스를 살펴보겠습니다.
// test/alphabet_position_test.rs
#[test]
fn it_should_ignore_non_characters() {
let replaced = alphabet_position("'a a. 2");
assert_eq!(replaced, "1 1");
}
자, 문자가 아닌 모든 항목을 건너뛰어 해당 테스트도 수정해 보겠습니다.
pub fn alphabet_position(s: &str) -> String {
s.to_lowercase()
.chars()
.filter(|x| x.is_alphabetic()) // <-- adding this line here
.map(|x| -> u8 { x as u8 - 'a' as u8 + 1 })
.map(|x| -> String { x.to_string() })
.collect::<Vec<String>>()
.join(" ")
}
좋아, 더 이상 코너 케이스가 생각나지 않았으므로 전체 테스트 케이스가 있으면 항상 확인하는 것이 좋습니다. 운 좋게도 우리는 챌린지 설명에서 무료로 하나를 얻었습니다.
#[test]
fn it_should_replace_the_sentence() {
let replaced = alphabet_position("The sunset sets at twelve o' clock.");
assert_eq!(
replaced,
"20 8 5 19 21 14 19 5 20 19 5 20 19 1 20 20 23 5 12 22 5 15 3 12 15 3 11"
);
}
그리고 보시다시피 테스트는 코드 변경 없이도 녹색입니다. 잘했어요 :)
사양 ftw
위에서 언급했듯이 이제 rspec과 같은 구문으로 테스트를 다시 작성하여 더욱 표현력 있게 만드는 방법을 보여주고 싶습니다. 이를 위해 편리한 캔디와 함께 제공되는 a crate called speculate을 사용합니다. 해당 종속성을 추가해 보겠습니다.
$ cat >> Cargo.toml
[dev-dependencies]
speculate = "0.1"
^D
데모를 위해 새 테스트 파일(
touch test/alphabet_position_spec.rs
)을 만들고 이전 파일을 유지합니다. 그러나 기존 것을 리팩토링할 수도 있습니다.// test/alphabet_position_spec.rs
use dev_challenge_47::alphabet_position;
use speculate::speculate;
speculate! { // <-- it's a macro but who cares
describe "alphabet_position" {
it "should replace 'a' with 1" {
assert_eq!(alphabet_position("a"), "1");
}
it "should replace 'A' with 1" {
assert_eq!(alphabet_position("A"), "1");
}
it "should ignore non characters" {
assert_eq!(alphabet_position("'a a. 2"), "1 1");
}
it "should replace the full test sentence" {
assert_eq!(
alphabet_position("The sunset sets at twelve o' clock."),
"20 8 5 19 21 14 19 5 20 19 5 20 19 1 20 20 23 5 12 22 5 15 3 12 15 3 11"
);
}
}
}
내 눈에는 아주 좋아보이는데 당신은 어때요?
내가 불평해야 하는 유일한 것은 실행할 때 출력
cargo test
입니다. 카르마 또는 다른 사람에서 익숙해진 것처럼 좋지 않습니다.running 4 tests
test speculate_0::alphabet_position::test_should_ignore_non_characters ... ok
test speculate_0::alphabet_position::test_should_replace_A_with_1 ... ok
test speculate_0::alphabet_position::test_should_replace_a_with_1 ... ok
test speculate_0::alphabet_position::test_should_replace_the_full_test_sentence ... ok
당신은 여전히 그것을 얻을 수 있고 코드는 더 표현력 있고 읽기 쉬워집니다. 그것은 이 멋진 상자를 사용하기에 충분히 중요합니다.
사용된 버전:
$ cargo --version && rustc --version
cargo 1.37.0 (9edd08916 2019-08-02)
rustc 1.37.0 (eae3437df 2019-08-13)
피드백을 공유하는 것을 잊지 마시고, 학습 내용이 있다면 알려주십시오.
The entire code can be found on github
Reference
이 문제에 관하여(작은 녹 시작 힌트 시리즈: 테스트 및 TDD), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/5422m4n/little-rust-starter-hint-series-tests-and-tdd-3jim텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)