mirror of
https://github.com/kbwo/testing-language-server.git
synced 2025-08-02 14:52:14 +00:00
feat: implement phpunit adapter
This commit is contained in:
parent
daa8db434c
commit
3e3d4c5db1
15 changed files with 2125 additions and 9 deletions
9
CONTRIBUTING.md
Normal file
9
CONTRIBUTING.md
Normal file
|
@ -0,0 +1,9 @@
|
|||
# Getting started
|
||||
|
||||
```sh
|
||||
cargo install just
|
||||
cargo install cargo-watch
|
||||
just watch-build
|
||||
sudo ln -s $(pwd)/target/debug/testing-language-server /usr/local/bin/testing-language-server
|
||||
sudo ln -s $(pwd)/target/debug/testing-ls-adapter /usr/local/bin/testing-ls-adapter
|
||||
```
|
19
Cargo.lock
generated
19
Cargo.lock
generated
|
@ -644,6 +644,7 @@ dependencies = [
|
|||
"tracing",
|
||||
"tracing-appender",
|
||||
"tracing-subscriber",
|
||||
"tree-sitter-php",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -665,7 +666,9 @@ dependencies = [
|
|||
"tree-sitter",
|
||||
"tree-sitter-go",
|
||||
"tree-sitter-javascript",
|
||||
"tree-sitter-php",
|
||||
"tree-sitter-rust",
|
||||
"xml-rs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -828,6 +831,16 @@ dependencies = [
|
|||
"tree-sitter",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tree-sitter-php"
|
||||
version = "0.22.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1be890bd043986cc26b69968698e508dbd40060805e482f226dc873a63a88d60"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"tree-sitter",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tree-sitter-rust"
|
||||
version = "0.21.2"
|
||||
|
@ -1040,3 +1053,9 @@ name = "windows_x86_64_msvc"
|
|||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
|
||||
|
||||
[[package]]
|
||||
name = "xml-rs"
|
||||
version = "0.8.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "539a77ee7c0de333dcc6da69b177380a0b81e0dacfa4f7344c465a36871ee601"
|
||||
|
|
|
@ -46,3 +46,4 @@ once_cell = { workspace = true }
|
|||
strum = { workspace = true, features = ["derive"] }
|
||||
glob = { workspace = true }
|
||||
globwalk = "0.9.1"
|
||||
tree-sitter-php = "0.22.8"
|
||||
|
|
|
@ -20,7 +20,9 @@ anyhow = { workspace = true }
|
|||
tempfile = "3.10.1"
|
||||
tree-sitter-javascript = "0.21.0"
|
||||
tree-sitter-go = "0.21.0"
|
||||
tree-sitter-php = "0.22.5"
|
||||
tracing-appender = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
tracing-subscriber = { workspace = true, default-features = false }
|
||||
dirs = "5.0.1"
|
||||
xml-rs = "0.8.21"
|
||||
|
|
|
@ -2,6 +2,7 @@ use crate::runner::cargo_nextest::CargoNextestRunner;
|
|||
use crate::runner::cargo_test::CargoTestRunner;
|
||||
use crate::runner::deno::DenoRunner;
|
||||
use crate::runner::go::GoTestRunner;
|
||||
use crate::runner::phpunit::PhpunitRunner;
|
||||
use crate::runner::vitest::VitestRunner;
|
||||
use std::str::FromStr;
|
||||
use testing_language_server::error::LSError;
|
||||
|
@ -19,6 +20,7 @@ pub enum AvailableTestKind {
|
|||
Vitest(VitestRunner),
|
||||
Deno(DenoRunner),
|
||||
GoTest(GoTestRunner),
|
||||
Phpunit(PhpunitRunner),
|
||||
}
|
||||
impl Runner for AvailableTestKind {
|
||||
fn discover(&self, args: DiscoverArgs) -> Result<(), LSError> {
|
||||
|
@ -29,6 +31,7 @@ impl Runner for AvailableTestKind {
|
|||
AvailableTestKind::Deno(runner) => runner.discover(args),
|
||||
AvailableTestKind::GoTest(runner) => runner.discover(args),
|
||||
AvailableTestKind::Vitest(runner) => runner.discover(args),
|
||||
AvailableTestKind::Phpunit(runner) => runner.discover(args),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,6 +43,7 @@ impl Runner for AvailableTestKind {
|
|||
AvailableTestKind::Deno(runner) => runner.run_file_test(args),
|
||||
AvailableTestKind::GoTest(runner) => runner.run_file_test(args),
|
||||
AvailableTestKind::Vitest(runner) => runner.run_file_test(args),
|
||||
AvailableTestKind::Phpunit(runner) => runner.run_file_test(args),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -51,6 +55,7 @@ impl Runner for AvailableTestKind {
|
|||
AvailableTestKind::Deno(runner) => runner.detect_workspaces(args),
|
||||
AvailableTestKind::GoTest(runner) => runner.detect_workspaces(args),
|
||||
AvailableTestKind::Vitest(runner) => runner.detect_workspaces(args),
|
||||
AvailableTestKind::Phpunit(runner) => runner.detect_workspaces(args),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -66,6 +71,7 @@ impl FromStr for AvailableTestKind {
|
|||
"go-test" => Ok(AvailableTestKind::GoTest(GoTestRunner)),
|
||||
"vitest" => Ok(AvailableTestKind::Vitest(VitestRunner)),
|
||||
"deno" => Ok(AvailableTestKind::Deno(DenoRunner)),
|
||||
"phpunit" => Ok(AvailableTestKind::Phpunit(PhpunitRunner)),
|
||||
_ => Err(anyhow::anyhow!("Unknown test kind: {}", s)),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,5 +3,6 @@ pub mod cargo_test;
|
|||
pub mod deno;
|
||||
pub mod go;
|
||||
pub mod jest;
|
||||
pub mod phpunit;
|
||||
pub mod util;
|
||||
pub mod vitest;
|
||||
|
|
338
crates/adapter/src/runner/phpunit.rs
Normal file
338
crates/adapter/src/runner/phpunit.rs
Normal file
|
@ -0,0 +1,338 @@
|
|||
use lsp_types::{Diagnostic, DiagnosticSeverity, Position, Range};
|
||||
use std::fs::File;
|
||||
use std::io::BufReader;
|
||||
use std::process::Output;
|
||||
use testing_language_server::error::LSError;
|
||||
use testing_language_server::spec::{
|
||||
DetectWorkspaceResult, DiscoverResult, DiscoverResultItem, RunFileTestResult,
|
||||
RunFileTestResultItem, TestItem,
|
||||
};
|
||||
use xml::reader::{ParserConfig, XmlEvent};
|
||||
|
||||
use crate::model::Runner;
|
||||
|
||||
use super::util::{
|
||||
detect_workspaces_from_file_paths, discover_with_treesitter, send_stdout, LOG_LOCATION,
|
||||
MAX_CHAR_LENGTH,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ResultFromXml {
|
||||
pub message: String,
|
||||
pub path: String,
|
||||
pub line: u32,
|
||||
}
|
||||
|
||||
impl Into<RunFileTestResultItem> for ResultFromXml {
|
||||
fn into(self) -> RunFileTestResultItem {
|
||||
RunFileTestResultItem {
|
||||
path: self.path,
|
||||
diagnostics: vec![Diagnostic {
|
||||
message: self.message,
|
||||
range: Range {
|
||||
start: Position {
|
||||
line: self.line - 1,
|
||||
character: 0,
|
||||
},
|
||||
end: Position {
|
||||
line: self.line - 1,
|
||||
character: MAX_CHAR_LENGTH,
|
||||
},
|
||||
},
|
||||
severity: Some(DiagnosticSeverity::ERROR),
|
||||
..Default::default()
|
||||
}],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn detect_workspaces(file_paths: Vec<String>) -> DetectWorkspaceResult {
|
||||
detect_workspaces_from_file_paths(&file_paths, &["composer.json".to_string()])
|
||||
}
|
||||
|
||||
fn get_result_from_characters(characters: &str) -> Result<ResultFromXml, anyhow::Error> {
|
||||
// characters can be like
|
||||
// Tests\\CalculatorTest::testFail1\nFailed asserting that 8 matches expected 1.\n\n/home/kbwo/projects/github.com/kbwo/testing-language-server/demo/phpunit/src/CalculatorTest.php:28
|
||||
let mut split = characters.split("\n\n");
|
||||
let message = split
|
||||
.next()
|
||||
.unwrap()
|
||||
.trim_start_matches("Failed asserting that ")
|
||||
.trim_end_matches(".")
|
||||
.to_string();
|
||||
let location = split.next().unwrap().to_string();
|
||||
let mut split_location = location.split(":");
|
||||
|
||||
let path = split_location.next().unwrap().to_string();
|
||||
let line = split_location.next().unwrap().parse().unwrap();
|
||||
Ok(ResultFromXml {
|
||||
message,
|
||||
path,
|
||||
line,
|
||||
})
|
||||
}
|
||||
|
||||
fn get_result_from_xml(path: &str) -> Result<Vec<ResultFromXml>, anyhow::Error> {
|
||||
use xml::common::Position;
|
||||
|
||||
let file = File::open(path).unwrap();
|
||||
let mut reader = ParserConfig::default()
|
||||
.ignore_root_level_whitespace(false)
|
||||
.create_reader(BufReader::new(file));
|
||||
|
||||
let local_name = "failure";
|
||||
|
||||
let mut in_failure = false;
|
||||
let mut result: Vec<ResultFromXml> = Vec::new();
|
||||
loop {
|
||||
match reader.next() {
|
||||
Ok(e) => match e {
|
||||
XmlEvent::StartElement { name, .. } => {
|
||||
if name.local_name.starts_with(local_name) {
|
||||
in_failure = true;
|
||||
}
|
||||
}
|
||||
XmlEvent::EndElement { .. } => {
|
||||
in_failure = false;
|
||||
}
|
||||
XmlEvent::Characters(data) => {
|
||||
if let Ok(result_from_xml) = get_result_from_characters(&data) {
|
||||
if in_failure {
|
||||
result.push(result_from_xml);
|
||||
}
|
||||
}
|
||||
}
|
||||
XmlEvent::EndDocument => break,
|
||||
_ => {}
|
||||
},
|
||||
Err(e) => {
|
||||
tracing::error!("Error at {}: {e}", reader.position());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn discover(file_path: &str) -> Result<Vec<TestItem>, LSError> {
|
||||
// from https://github.com/olimorris/neotest-phpunit/blob/bbd79d95e927ccd16f0e1d765060058d34838e2e/lua/neotest-phpunit/init.lua#L111
|
||||
// license: https://github.com/olimorris/neotest-phpunit/blob/bbd79d95e927ccd16f0e1d765060058d34838e2e/LICENSE
|
||||
let query = r#"
|
||||
((class_declaration
|
||||
name: (name) @namespace.name (#match? @namespace.name "Test")
|
||||
)) @namespace.definition
|
||||
|
||||
((method_declaration
|
||||
(attribute_list
|
||||
(attribute_group
|
||||
(attribute) @test_attribute (#match? @test_attribute "Test")
|
||||
)
|
||||
)
|
||||
(
|
||||
(visibility_modifier)
|
||||
(name) @test.name
|
||||
) @test.definition
|
||||
))
|
||||
|
||||
((method_declaration
|
||||
(name) @test.name (#match? @test.name "test")
|
||||
)) @test.definition
|
||||
|
||||
(((comment) @test_comment (#match? @test_comment "\\@test") .
|
||||
(method_declaration
|
||||
(name) @test.name
|
||||
) @test.definition
|
||||
))
|
||||
"#;
|
||||
discover_with_treesitter(file_path, &tree_sitter_php::language_php(), query)
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Debug)]
|
||||
pub struct PhpunitRunner;
|
||||
|
||||
impl Runner for PhpunitRunner {
|
||||
fn discover(&self, args: testing_language_server::spec::DiscoverArgs) -> Result<(), LSError> {
|
||||
let file_paths = args.file_paths;
|
||||
let mut discover_results: DiscoverResult = vec![];
|
||||
for file_path in file_paths {
|
||||
discover_results.push(DiscoverResultItem {
|
||||
tests: discover(&file_path)?,
|
||||
path: file_path,
|
||||
})
|
||||
}
|
||||
send_stdout(&discover_results)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run_file_test(
|
||||
&self,
|
||||
args: testing_language_server::spec::RunFileTestArgs,
|
||||
) -> Result<(), LSError> {
|
||||
let file_paths = args.file_paths;
|
||||
let workspace_root = args.workspace;
|
||||
let log_path = LOG_LOCATION.join("phpunit.xml");
|
||||
let tests = file_paths
|
||||
.iter()
|
||||
.map(|path| {
|
||||
discover(path).map(|test_items| {
|
||||
test_items
|
||||
.into_iter()
|
||||
.map(|item| item.id)
|
||||
.collect::<Vec<String>>()
|
||||
})
|
||||
})
|
||||
.filter_map(Result::ok)
|
||||
.flatten()
|
||||
.collect::<Vec<_>>();
|
||||
let test_names = tests.join("|");
|
||||
let filter_pattern = format!("/{test_names}/");
|
||||
let output = std::process::Command::new("phpunit")
|
||||
.current_dir(&workspace_root)
|
||||
.args([
|
||||
"--log-junit",
|
||||
log_path.to_str().unwrap(),
|
||||
"--filter",
|
||||
&filter_pattern,
|
||||
])
|
||||
.args(file_paths)
|
||||
.stdout(std::process::Stdio::null())
|
||||
.stderr(std::process::Stdio::null())
|
||||
.output()
|
||||
.unwrap();
|
||||
let Output { stdout, stderr, .. } = output;
|
||||
if stdout.is_empty() && !stderr.is_empty() {
|
||||
return Err(LSError::Adapter(String::from_utf8(stderr).unwrap()));
|
||||
}
|
||||
let result_from_xml = get_result_from_xml(log_path.to_str().unwrap())?;
|
||||
let diagnostics: RunFileTestResult = result_from_xml
|
||||
.into_iter()
|
||||
.map(|result_from_xml| {
|
||||
let result_item: RunFileTestResultItem = result_from_xml.into();
|
||||
result_item
|
||||
})
|
||||
.collect();
|
||||
send_stdout(&diagnostics)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn detect_workspaces(
|
||||
&self,
|
||||
args: testing_language_server::spec::DetectWorkspaceArgs,
|
||||
) -> Result<(), LSError> {
|
||||
let file_paths = args.file_paths;
|
||||
let detect_result = detect_workspaces(file_paths);
|
||||
send_stdout(&detect_result)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use lsp_types::{Position, Range};
|
||||
|
||||
use crate::runner::util::MAX_CHAR_LENGTH;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn parse_xml() {
|
||||
let mut path = std::env::current_dir().unwrap();
|
||||
path.push("../../demo/phpunit/output.xml");
|
||||
let result = get_result_from_xml(path.to_str().unwrap()).unwrap();
|
||||
assert_eq!(result.len(), 1);
|
||||
assert_eq!(
|
||||
result[0].message,
|
||||
"Tests\\CalculatorTest::testFail1\nFailed asserting that 8 matches expected 1"
|
||||
);
|
||||
assert_eq!(
|
||||
result[0].path,
|
||||
"/home/kbwo/testing-language-server/demo/phpunit/src/CalculatorTest.php"
|
||||
);
|
||||
assert_eq!(result[0].line, 28);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_discover() {
|
||||
let file_path = "../../demo/phpunit/src/CalculatorTest.php";
|
||||
let test_items = discover(file_path).unwrap();
|
||||
assert_eq!(test_items.len(), 3);
|
||||
assert_eq!(
|
||||
test_items,
|
||||
[
|
||||
TestItem {
|
||||
id: "CalculatorTest::testAdd".to_string(),
|
||||
name: "CalculatorTest::testAdd".to_string(),
|
||||
start_position: Range {
|
||||
start: Position {
|
||||
line: 9,
|
||||
character: 4
|
||||
},
|
||||
end: Position {
|
||||
line: 9,
|
||||
character: MAX_CHAR_LENGTH
|
||||
}
|
||||
},
|
||||
end_position: Range {
|
||||
start: Position {
|
||||
line: 14,
|
||||
character: 0
|
||||
},
|
||||
end: Position {
|
||||
line: 14,
|
||||
character: 5
|
||||
}
|
||||
}
|
||||
},
|
||||
TestItem {
|
||||
id: "CalculatorTest::testSubtract".to_string(),
|
||||
name: "CalculatorTest::testSubtract".to_string(),
|
||||
start_position: Range {
|
||||
start: Position {
|
||||
line: 16,
|
||||
character: 4
|
||||
},
|
||||
end: Position {
|
||||
line: 16,
|
||||
character: MAX_CHAR_LENGTH
|
||||
}
|
||||
},
|
||||
end_position: Range {
|
||||
start: Position {
|
||||
line: 21,
|
||||
character: 0
|
||||
},
|
||||
end: Position {
|
||||
line: 21,
|
||||
character: 5
|
||||
}
|
||||
}
|
||||
},
|
||||
TestItem {
|
||||
id: "CalculatorTest::testFail1".to_string(),
|
||||
name: "CalculatorTest::testFail1".to_string(),
|
||||
start_position: Range {
|
||||
start: Position {
|
||||
line: 23,
|
||||
character: 4
|
||||
},
|
||||
end: Position {
|
||||
line: 23,
|
||||
character: MAX_CHAR_LENGTH
|
||||
}
|
||||
},
|
||||
end_position: Range {
|
||||
start: Position {
|
||||
line: 28,
|
||||
character: 0
|
||||
},
|
||||
end: Position {
|
||||
line: 28,
|
||||
character: 5
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
)
|
||||
}
|
||||
}
|
|
@ -3,17 +3,17 @@
|
|||
"testing": {
|
||||
"command": "testing-language-server",
|
||||
"trace.server": "verbose",
|
||||
"filetypes": ["rust", "javascript", "go", "typescript"],
|
||||
"filetypes": ["rust", "javascript", "go", "typescript", "php"],
|
||||
"initializationOptions": {
|
||||
"adapterCommand": {
|
||||
// "cargo-test": [
|
||||
// {
|
||||
// "path": "testing-ls-adapter",
|
||||
// "extra_args": ["--test-kind=cargo-test"],
|
||||
// "include_patterns": ["/**/src/**/*.rs"],
|
||||
// "exclude_patterns": ["/**/target/**"]
|
||||
// }
|
||||
// ],
|
||||
"cargo-test": [
|
||||
{
|
||||
"path": "testing-ls-adapter",
|
||||
"extra_args": ["--test-kind=cargo-test"],
|
||||
"include_patterns": ["/**/src/**/*.rs"],
|
||||
"exclude_patterns": ["/**/target/**"]
|
||||
}
|
||||
],
|
||||
"cargo-nextest": [
|
||||
{
|
||||
"path": "testing-ls-adapter",
|
||||
|
@ -56,6 +56,14 @@
|
|||
"include_patterns": ["/**/*.go"],
|
||||
"exclude_patterns": []
|
||||
}
|
||||
],
|
||||
"phpunit": [
|
||||
{
|
||||
"path": "testing-ls-adapter",
|
||||
"extra_args": ["--test-kind=phpunit"],
|
||||
"include_patterns": ["/**/*Test.php"],
|
||||
"exclude_patterns": ["/phpunit/vendor/**/*.php"]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
1
demo/phpunit/.gitignore
vendored
Normal file
1
demo/phpunit/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
vendor
|
2
demo/phpunit/.mise.toml
Normal file
2
demo/phpunit/.mise.toml
Normal file
|
@ -0,0 +1,2 @@
|
|||
[tools]
|
||||
php = "8.3"
|
17
demo/phpunit/composer.json
Normal file
17
demo/phpunit/composer.json
Normal file
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"name": "kbwo/phpunit",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"App\\": "src/"
|
||||
}
|
||||
},
|
||||
"authors": [
|
||||
{
|
||||
"name": "kbwo",
|
||||
"email": "kabaaa1126@gmail.com"
|
||||
}
|
||||
],
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^11.3"
|
||||
}
|
||||
}
|
1651
demo/phpunit/composer.lock
generated
Normal file
1651
demo/phpunit/composer.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
15
demo/phpunit/output.xml
Normal file
15
demo/phpunit/output.xml
Normal file
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<testsuites>
|
||||
<testsuite name="CLI Arguments" tests="3" assertions="3" errors="0" failures="1" skipped="0" time="0.002791">
|
||||
<testsuite name="Tests\CalculatorTest" file="/home/kbwo/testing-language-server/demo/phpunit/src/CalculatorTest.php" tests="3" assertions="3" errors="0" failures="1" skipped="0" time="0.002791">
|
||||
<testcase name="testAdd" file="/home/kbwo/testing-language-server/demo/phpunit/src/CalculatorTest.php" line="10" class="Tests\CalculatorTest" classname="Tests.CalculatorTest" assertions="1" time="0.000695"/>
|
||||
<testcase name="testSubtract" file="/home/kbwo/testing-language-server/demo/phpunit/src/CalculatorTest.php" line="17" class="Tests\CalculatorTest" classname="Tests.CalculatorTest" assertions="1" time="0.000046"/>
|
||||
<testcase name="testFail1" file="/home/kbwo/testing-language-server/demo/phpunit/src/CalculatorTest.php" line="24" class="Tests\CalculatorTest" classname="Tests.CalculatorTest" assertions="1" time="0.002051">
|
||||
<failure type="PHPUnit\Framework\ExpectationFailedException">Tests\CalculatorTest::testFail1
|
||||
Failed asserting that 8 matches expected 1.
|
||||
|
||||
/home/kbwo/testing-language-server/demo/phpunit/src/CalculatorTest.php:28</failure>
|
||||
</testcase>
|
||||
</testsuite>
|
||||
</testsuite>
|
||||
</testsuites>
|
16
demo/phpunit/src/Calculator.php
Normal file
16
demo/phpunit/src/Calculator.php
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
namespace App;
|
||||
|
||||
class Calculator
|
||||
{
|
||||
public function add($a, $b)
|
||||
{
|
||||
return $a + $b;
|
||||
}
|
||||
|
||||
public function subtract($a, $b)
|
||||
{
|
||||
return $a - $b;
|
||||
}
|
||||
}
|
30
demo/phpunit/src/CalculatorTest.php
Normal file
30
demo/phpunit/src/CalculatorTest.php
Normal file
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace Tests;
|
||||
|
||||
use App\Calculator;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class CalculatorTest extends TestCase
|
||||
{
|
||||
public function testAdd()
|
||||
{
|
||||
$calculator = new Calculator();
|
||||
$result = $calculator->add(2, 3);
|
||||
$this->assertEquals(5, $result);
|
||||
}
|
||||
|
||||
public function testSubtract()
|
||||
{
|
||||
$calculator = new Calculator();
|
||||
$result = $calculator->subtract(5, 3);
|
||||
$this->assertEquals(2, $result);
|
||||
}
|
||||
|
||||
public function testFail1()
|
||||
{
|
||||
$calculator = new Calculator();
|
||||
$result = $calculator->subtract(10, 2);
|
||||
$this->assertEquals(1, $result);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue