fix: Better handle the overload test methods (#1526)

- change the test id of JUnit 5 and TestNG. The new test id of these two frameworks 
   will contain the method parameter types, so that users can specify any one of the
   overload test methods and see the results.
- update the contribution guide.
- add some test cases for TestNG.
This commit is contained in:
Kropie 2023-02-08 20:13:09 -06:00 коммит произвёл GitHub
Родитель 0c14d0b92e
Коммит d46a5923f9
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
17 изменённых файлов: 1900 добавлений и 882 удалений

11
.vscode/launch.json поставляемый
Просмотреть файл

@ -31,7 +31,11 @@
"runtimeExecutable": "${execPath}",
"args": ["${workspaceFolder}/test/test-projects/junit", "--extensionDevelopmentPath=${workspaceFolder}", "--extensionTestsPath=${workspaceFolder}/out/test/suite" ],
"sourceMaps": true,
"outFiles": [ "${workspaceFolder}/dist/**/*.js" ],
"pauseForSourceMap": true,
"outFiles": [
"${workspaceFolder}/dist/**/*.js",
"${workspaceFolder}/out/**/*.js"
],
"preLaunchTask": "npm: compile"
},
{
@ -41,7 +45,10 @@
"runtimeExecutable": "${execPath}",
"args": ["${workspaceFolder}/test/test-projects/simple", "--extensionDevelopmentPath=${workspaceFolder}", "--extensionTestsPath=${workspaceFolder}/out/test/unmanaged-folder-suite" ],
"sourceMaps": true,
"outFiles": [ "${workspaceFolder}/dist/**/*.js" ],
"outFiles": [
"${workspaceFolder}/dist/**/*.js",
"${workspaceFolder}/out/**/*.js"
],
"preLaunchTask": "npm: compile"
}
]

Просмотреть файл

@ -64,3 +64,14 @@ If you want to build your own private build, run `npx @vscode/vsce@latest packag
### Check Lint Errors:
Run `npm run lint` to check lint errors.
## Running the test suite
You can run tests using `npm run test` or by using the `Launch Tests` Run and Debug configurations in VS Code.
### VS Code run and debug configurations
There are two test suite folders for this project. In VS Code you'll see the following run targets:
- `Launch Tests (maven junit)`: This will run the tests in the `./test/suite` folder.
- `Launch Tests (unmanaged-folder)`: This will run the tests in the `./test/unmanaged-folder-suite` folder.

Просмотреть файл

@ -74,7 +74,7 @@ public class JavaTestItemBuilder {
} else {
displayName = JavaElementLabels.getElementLabel(this.element, JavaElementLabels.ALL_DEFAULT);
}
final String fullName = TestItemUtils.parseFullName(this.element, this.level);
final String fullName = TestItemUtils.parseFullName(this.element, this.level, this.kind);
if (uri == null) {
uri = JDTUtils.getFileURI(this.element.getResource());
}

Просмотреть файл

@ -11,8 +11,8 @@
package com.microsoft.java.test.plugin.util;
import com.microsoft.java.test.plugin.model.TestKind;
import com.microsoft.java.test.plugin.model.TestLevel;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.ISourceRange;
@ -21,6 +21,7 @@ import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.SourceRange;
import org.eclipse.jdt.ls.core.internal.JDTUtils;
import org.eclipse.jdt.ls.core.internal.hover.JavaElementLabels;
import org.eclipse.lsp4j.Range;
@SuppressWarnings("restriction")
@ -39,14 +40,23 @@ public class TestItemUtils {
return null;
}
public static String parseFullName(IJavaElement element, TestLevel level) {
public static String parseFullName(IJavaElement element, TestLevel level, TestKind kind) {
switch (level) {
case CLASS:
final IType type = (IType) element;
return type.getFullyQualifiedName();
case METHOD:
final IMethod method = (IMethod) element;
return method.getDeclaringType().getFullyQualifiedName() + "#" + method.getElementName();
if (kind == TestKind.JUnit5 || kind == TestKind.TestNG) {
final String className = method.getDeclaringType().getFullyQualifiedName();
// Generics don't come through in the test results, so we need to strip
// them out now.
final String methodName = JavaElementLabels.getElementLabel(element, JavaElementLabels.ALL_DEFAULT)
.replaceAll("<.*?>", "");
return className + "#" + methodName;
} else {
return method.getDeclaringType().getFullyQualifiedName() + "#" + method.getElementName();
}
default:
return element.getElementName();
}

Просмотреть файл

@ -49,16 +49,16 @@ public class TestNGLauncher implements ITestLauncher {
return classToMethodsMap;
}
private static String getClassName(String clazz) throws ClassNotFoundException {
return Class.forName(clazz, false, TestNGLauncher.class.getClassLoader()).getName();
private static String getClassName(String testId) throws ClassNotFoundException {
return Class.forName(testId, false, TestNGLauncher.class.getClassLoader()).getName();
}
private static String getClassNameFromMethod(String clazz) throws ClassNotFoundException {
return Class.forName(clazz.substring(0, clazz.lastIndexOf("#")), false,
private static String getClassNameFromMethod(String testId) throws ClassNotFoundException {
return Class.forName(testId.substring(0, testId.lastIndexOf("#")), false,
TestNGLauncher.class.getClassLoader()).getName();
}
private static String getMethodName(String clazz) {
return clazz.substring(clazz.lastIndexOf("#") + 1);
private static String getMethodName(String testId) {
return testId.substring(testId.lastIndexOf("#") + 1);
}
}

Просмотреть файл

@ -27,19 +27,19 @@ public class TestNGListener
@Override
public void onTestStart(ITestResult result) {
TestRunnerMessageHelper.testStarted(result.getTestClass().getName() + "#" + result.getName());
TestRunnerMessageHelper.testStarted(createTestName(result));
}
@Override
public void onTestSuccess(ITestResult result) {
final long duration = result.getEndMillis() - result.getStartMillis();
TestRunnerMessageHelper.testFinished(result.getTestClass().getName() + "#" + result.getName(), duration);
TestRunnerMessageHelper.testFinished(createTestName(result), duration);
}
@Override
public void onTestFailure(ITestResult result) {
final long duration = result.getEndMillis() - result.getStartMillis();
TestRunnerMessageHelper.testFailed(result.getTestClass().getName() + "#" + result.getName(),
TestRunnerMessageHelper.testFailed(createTestName(result),
result.getThrowable(), duration);
}
@ -57,7 +57,7 @@ public class TestNGListener
onTestFailure(result);
return;
}
TestRunnerMessageHelper.testIgnored(result.getTestClass().getName() + "#" + result.getName());
TestRunnerMessageHelper.testIgnored(createTestName(result));
}
@Override
@ -65,6 +65,24 @@ public class TestNGListener
onTestFailure(result);
}
private String createTestName(ITestResult result) {
final String className = result.getTestClass().getName();
final String methodName = result.getMethod().getMethodName();
final StringBuilder params = new StringBuilder();
for (final Class<?> paramClazz : result.getMethod().getParameterTypes()) {
params.append(paramClazz.getSimpleName().replaceAll("<.*?>", ""));
params.append(", ");
}
// Remove the last ", "
if (params.length() > 0) {
params.delete(params.length() - 2, params.length());
}
return className + "#" + methodName + "(" + params.toString() + ")";
}
@Override
public void onStart(ITestContext context) {
}
@ -82,7 +100,8 @@ public class TestNGListener
}
@Override
public void onConfigurationSuccess(ITestResult itr) {}
public void onConfigurationSuccess(ITestResult itr) {
}
@Override
public void onConfigurationFailure(ITestResult result) {
@ -90,5 +109,6 @@ public class TestNGListener
}
@Override
public void onConfigurationSkip(ITestResult result) {}
public void onConfigurationSkip(ITestResult result) {
}
}

Просмотреть файл

@ -40,7 +40,7 @@ public class TestNGRunner {
// backward compatibility
testNG.addListener((ITestListener) listener);
}
testNG.setXmlSuites(Collections.singletonList(suite));
testNG.run();
}
@ -49,7 +49,7 @@ public class TestNGRunner {
final XmlTest test = new XmlTest(suite);
test.setName("TestNGTest-" + UUID.randomUUID().toString());
final List<XmlClass> classes = new ArrayList<>();
for (final Entry<String, List<String>> entry: map.entrySet()) {
for (final Entry<String, List<String>> entry : map.entrySet()) {
classes.add(createClass(entry.getKey(), entry.getValue()));
}
test.setXmlClasses(classes);
@ -59,8 +59,8 @@ public class TestNGRunner {
final XmlClass xmlClass = new XmlClass(clazz);
if (methods.size() != 0) {
final List<XmlInclude> includes = new ArrayList<>();
for (final String method: methods) {
includes.add(new XmlInclude(method));
for (final String method : methods) {
includes.add(new XmlInclude(method.replaceAll("\\(.*\\)", "")));
}
xmlClass.setIncludedMethods(includes);
}

2422
package-lock.json сгенерированный

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -69,7 +69,7 @@
"./server/junit-vintage-engine_5.9.0.jar",
"./server/org.apiguardian.api_1.1.2.jar",
"./server/org.eclipse.jdt.junit4.runtime_1.3.0.v20220609-1843.jar",
"./server/org.eclipse.jdt.junit5.runtime_1.1.0.v20220715-1030.jar",
"./server/org.eclipse.jdt.junit5.runtime_1.1.100.v20220907-0450.jar",
"./server/org.opentest4j_1.2.0.v20211018-1956.jar",
"./server/com.microsoft.java.test.plugin-0.37.1.jar"
],

Просмотреть файл

@ -184,6 +184,69 @@ export class JUnitRunnerResultAnalyzer extends RunnerResultAnalyzer {
}
protected getTestId(message: string): string {
if (message.includes('engine:junit5') || message.includes('engine:junit-jupiter') || message.includes('engine:jqwik')) {
return this.getTestIdForJunit5Method(message);
} else {
return this.getTestIdForNonJunit5Method(message);
}
}
protected getTestIdForJunit5Method(message: string): string {
const classId: string = 'class:';
const nestedClassId: string = 'nested-class:';
const methodId: string = 'method:';
// Property id is for jqwik
const propertyId: string = 'property:';
const testTemplateId: string = 'test-template:';
// We're expecting something like:
// [engine:junit5]/[class:com.example.MyTest]/[method:myTest]/[test-template:myTest(String\, int)]
const parts: string[] = message.split('/');
let className: string = '';
let methodName: string = '';
if (!parts || parts.length === 0) {
// The pattern doesn't match what we're expecting, so we'll go ahead and defer to the non JUnit5 method.
return this.getTestIdForNonJunit5Method(message);
}
parts.forEach((part: string) => {
// Remove the leading and trailing brackets.
part = part.trim().replace(/\[/g, '').replace(/\]/g, '');
if (part.startsWith(classId)) {
className = part.substring(classId.length);
} else if (part.startsWith(methodId)) {
const rawMethodName: string = part.substring(methodId.length);
// If the method name exists then we want to include the '#' qualifier.
methodName = `#${this.getJUnit5MethodName(rawMethodName)}`;
} else if (part.startsWith(nestedClassId)) {
const nestedClassName: string = part.substring(nestedClassId.length);
className = `${className}$${nestedClassName}`;
} else if (part.startsWith(testTemplateId)) {
const rawMethodName: string = part.substring(testTemplateId.length)
.replace('\\,', ',')
.replace(' ', '');
// If the method name exists then we want to include the '#' qualifier.
methodName = `#${this.getJUnit5MethodName(rawMethodName)}`;
} else if (part.startsWith(propertyId)) {
const rawMethodName: string = part.substring(propertyId.length)
.replace('\\,', ',')
.replace(' ', '');
// If the method name exists then we want to include the '#' qualifier.
methodName = `#${this.getJUnit5MethodName(rawMethodName)}`;
}
});
if (className) {
return `${this.projectName}@${className}${methodName}`;
} else {
return `${this.projectName}@${message}`;
}
}
protected getTestIdForNonJunit5Method(message: string): string {
/**
* The following regex expression is used to parse the test runner's output, which match the following components:
* '(?:@AssumptionFailure: |@Ignore: )?' - indicate if the case is ignored due to assumption failure or disabled
@ -206,6 +269,27 @@ export class JUnitRunnerResultAnalyzer extends RunnerResultAnalyzer {
return `${this.projectName}@${message}`;
}
protected getJUnit5MethodName(rawName: string): string {
// Let's start by grabbing the text between the parentheses.
let rawParamsString: string = rawName.substring(rawName.indexOf('(') + 1, rawName.indexOf(')'));
// We're going to replace any '$' characters with '.' characters to simplify the following logic.
// NOTE: you will get '$' characters in the name if you have a nested class.
rawParamsString = rawParamsString.replace(/\$/g, '.');
const params: string[] = rawParamsString.split(',');
let paramString: string = '';
params.forEach((param: string) => {
paramString += `${param.substring(param.lastIndexOf('.') + 1)}, `;
});
// We want to remove the final comma.
if (paramString.length > 0) {
paramString = paramString.substring(0, paramString.length - 2);
}
const methodName: string = rawName.substring(0, rawName.indexOf('('));
return `${methodName}(${paramString})`;
}
private setCurrentState(testItem: TestItem, resultState: TestResultState, duration: number): void {
this.currentStates.set(testItem, { resultState, duration });
}
@ -248,7 +332,7 @@ export class JUnitRunnerResultAnalyzer extends RunnerResultAnalyzer {
const result: RegExpMatchArray | null = message.match(regExp);
if (result && result.length > 6) {
const index: string = result[0];
const testId: string = this.getTestId(result[1]);
const testId: string = this.getTestId(result[result.length - 1]);
const isSuite: boolean = result[2] === 'true';
const testCount: number = parseInt(result[3], 10);
const isDynamic: boolean = result[4] === 'true';
@ -264,23 +348,7 @@ export class JUnitRunnerResultAnalyzer extends RunnerResultAnalyzer {
if (parent) {
const parentData: ITestItemData | undefined = dataCache.get(parent);
if (parentData?.testLevel === TestLevel.Method) {
testItem = updateOrCreateTestItem(parent, {
children: [],
uri: parent.uri?.toString(),
range: parent.range,
jdtHandler: parentData.jdtHandler,
fullName: parentData.fullName,
label: this.getTestMethodName(displayName),
// prefer uniqueId, as it does not change when re-running only a single invocation:
id: uniqueId ? `${INVOCATION_PREFIX}${uniqueId}`
: `${INVOCATION_PREFIX}${parent.id}[#${parent.children.size + 1}]`,
projectName: parentData.projectName,
testKind: parentData.testKind,
testLevel: TestLevel.Invocation,
uniqueId,
// We will just create a string padded with the character "a" to provide easy sorting.
sortText: ''.padStart(parent.children.size + 1, 'a')
});
testItem = this.enlistDynamicMethodToTestMapping(testItem, parent, parentData, displayName, uniqueId);
}
}
} else {
@ -336,6 +404,28 @@ export class JUnitRunnerResultAnalyzer extends RunnerResultAnalyzer {
}
}
// Leaving this public so that it can be mocked when testing.
public enlistDynamicMethodToTestMapping(testItem: TestItem | undefined, parent: TestItem, parentData: ITestItemData, displayName: string, uniqueId: string | undefined): TestItem {
testItem = updateOrCreateTestItem(parent, {
children: [],
uri: parent.uri?.toString(),
range: parent.range,
jdtHandler: parentData.jdtHandler,
fullName: parentData.fullName,
label: this.getTestMethodName(displayName),
// prefer uniqueId, as it does not change when re-running only a single invocation:
id: uniqueId ? `${INVOCATION_PREFIX}${uniqueId}`
: `${INVOCATION_PREFIX}${parent.id}[#${parent.children.size + 1}]`,
projectName: parentData.projectName,
testKind: parentData.testKind,
testLevel: TestLevel.Invocation,
uniqueId,
// We will just create a string padded with the character "a" to provide easy sorting.
sortText: ''.padStart(parent.children.size + 1, 'a')
});
return testItem;
}
private async tryAppendMessage(item: TestItem, testMessage: TestMessage, testState: TestResultState): Promise<void> {
if (this.testMessageLocation) {
testMessage.location = this.testMessageLocation;
@ -373,6 +463,10 @@ export class JUnitRunnerResultAnalyzer extends RunnerResultAnalyzer {
* Get the test item label without the codicon prefix.
*/
private getLabelWithoutCodicon(name: string): string {
if (name.includes('#')) {
name = name.substring(name.indexOf('#') + 1);
}
const result: RegExpMatchArray | null = name.match(/(?:\$\(.+\) )?(.*)/);
if (result?.length === 2) {
return result[1];

Просмотреть файл

@ -27,8 +27,8 @@ suite('JUnit Runner Analyzer Tests for JUnit5 Parallel Tests', () => {
setup(() => {
testController = tests.createTestController('testController', 'Mock Test');
const testItemParent = generateTestItem(testController, 'junit@junit5.ParallelExecutionTest', TestKind.JUnit5, new Range(0, 0, 0, 0), undefined, 'ParallelExecutionTest.java');
testItem1 = generateTestItem(testController, 'junit@junit5.ParallelExecutionTest#test1', TestKind.JUnit5, new Range(1, 0, 1, 0), undefined, 'ParallelExecutionTest.java');
testItem2 = generateTestItem(testController, 'junit@junit5.ParallelExecutionTest#test2', TestKind.JUnit5, new Range(2, 0, 2, 0), undefined, 'ParallelExecutionTest.java');
testItem1 = generateTestItem(testController, 'junit@junit5.ParallelExecutionTest#test1()', TestKind.JUnit5, new Range(1, 0, 1, 0), undefined, 'ParallelExecutionTest.java');
testItem2 = generateTestItem(testController, 'junit@junit5.ParallelExecutionTest#test2()', TestKind.JUnit5, new Range(2, 0, 2, 0), undefined, 'ParallelExecutionTest.java');
testItemParent.children.add(testItem1);
testItemParent.children.add(testItem2);
const testRunRequest = new TestRunRequest([testItemParent], []);

Просмотреть файл

@ -228,7 +228,7 @@ java.lang.RuntimeException
});
test("test diff with line separators", () => {
const testItem = generateTestItem(testController, 'junit@junit5.TestAnnotation#shouldFail2', TestKind.JUnit5, new Range(8, 0, 10, 0));
const testItem = generateTestItem(testController, 'junit@junit5.TestAnnotation#shouldFail2()', TestKind.JUnit5, new Range(8, 0, 10, 0));
const testRunRequest = new TestRunRequest([testItem], []);
const testRun = testController.createTestRun(testRunRequest);
const startedSpy = sinon.spy(testRun, 'started');
@ -283,63 +283,80 @@ org.junit.ComparisonFailure: expected:<hello
assert.strictEqual(testMessage.location?.range.start.line, 8);
});
// The following test also tests JUnit 5 test classes that contain two
// methods with the same name but different signatures.
test("test JUnit 5's display name", () => {
const testItem = generateTestItem(testController, 'junit@junit5.TestAnnotation#test', TestKind.JUnit5, new Range(8, 0, 10, 0));
let testRunRequest = new TestRunRequest([testItem], []);
const testItem = generateTestItem(testController, 'junit@junit5.TestAnnotation#test()', TestKind.JUnit5, new Range(8, 0, 10, 0));
const testItemWithParams = generateTestItem(testController, 'junit@junit5.TestAnnotation#test(int)', TestKind.JUnit5, new Range(14, 0, 16, 0));
let testRunRequest = new TestRunRequest([testItem, testItemWithParams], []);
let testRun = testController.createTestRun(testRunRequest);
let testRunnerOutput = `%TESTC 1 v2
%TSTTREE2,junit5.TestAnnotation,true,1,false,1,TestAnnotation,,[engine:junit-jupiter]/[class:junit5.TestAnnotation]
%TSTTREE2,junit5.TestAnnotation,true,2,false,1,TestAnnotation,,[engine:junit-jupiter]/[class:junit5.TestAnnotation]
%TSTTREE3,test(junit5.TestAnnotation),false,1,false,2,hi,,[engine:junit-jupiter]/[class:junit5.TestAnnotation]/[method:test()]
%TSTTREE4,test(junit5.TestAnnotation),true,0,false,2,hi_with_params,int,[engine:junit-jupiter]/[class:junit5.TestAnnotation]/[test-template:test(int)]
%TESTS 3,test(junit5.TestAnnotation)
%TESTE 3,test(junit5.TestAnnotation)
%TSTTREE5,test(junit5.TestAnnotation),false,1,true,4,[1] 1,int,[engine:junit-jupiter]/[class:junit5.TestAnnotation]/[test-template:test(int)]/[test-template-invocation:#1]
%TESTS 5,test(junit5.TestAnnotation)
%TESTE 5,test(junit5.TestAnnotation)
%RUNTIME86`;
let runnerContext: IRunTestContext = {
isDebug: false,
kind: TestKind.JUnit5,
projectName: 'junit',
testItems: [testItem],
testItems: [testItem, testItemWithParams],
testRun: testRun,
workspaceFolder: workspace.workspaceFolders?.[0]!,
};
let analyzer = new JUnitRunnerResultAnalyzer(runnerContext);
let analyzer = new JUnitRunnerResultAnalyzer(runnerContext)
// We need to stub this method to avoid isssues with the TestController
// not being set up in the non-test version of the utils file.
const stub = sinon.stub(analyzer, "enlistDynamicMethodToTestMapping");
stub.returnsArg(0);
analyzer.analyzeData(testRunnerOutput);
assert.strictEqual(testItem.description, 'hi');
assert.strictEqual(testItemWithParams.description, 'hi_with_params');
// Remove the @DisplayName annotation
testRunRequest = new TestRunRequest([testItem], []);
testRunRequest = new TestRunRequest([testItem, testItemWithParams], []);
testRun = testController.createTestRun(testRunRequest);
testRunnerOutput = `%TESTC 1 v2
%TSTTREE2,junit5.TestAnnotation,true,1,false,1,TestAnnotation,,[engine:junit-jupiter]/[class:junit5.TestAnnotation]
%TSTTREE2,junit5.TestAnnotation,true,2,false,1,TestAnnotation,,[engine:junit-jupiter]/[class:junit5.TestAnnotation]
%TSTTREE3,test(junit5.TestAnnotation),false,1,false,2,test(),,[engine:junit-jupiter]/[class:junit5.TestAnnotation]/[method:test()]
%TSTTREE4,test(junit5.TestAnnotation),true,0,false,2,test(int),int,[engine:junit-jupiter]/[class:junit5.TestAnnotation]/[test-template:test(int)]
%TESTS 3,test(junit5.TestAnnotation)
%TESTE 3,test(junit5.TestAnnotation)
%TSTTREE5,test(junit5.TestAnnotation),false,1,true,4,[1] 1,int,[engine:junit-jupiter]/[class:junit5.TestAnnotation]/[test-template:test(int)]/[test-template-invocation:#1]
%TESTS 5,test(junit5.TestAnnotation)
%TESTE 5,test(junit5.TestAnnotation)
%RUNTIME81`;
runnerContext = {
isDebug: false,
kind: TestKind.JUnit5,
projectName: 'junit',
testItems: [testItem],
testItems: [testItem, testItemWithParams],
testRun: testRun,
workspaceFolder: workspace.workspaceFolders?.[0]!,
};
analyzer = new JUnitRunnerResultAnalyzer(runnerContext);
// We need to stub this method to avoid isssues with the TestController
// not being set up in the non-test version of the utils file.
sinon.stub(analyzer, "enlistDynamicMethodToTestMapping");
analyzer.analyzeData(testRunnerOutput);
assert.strictEqual(testItem.description, '');
assert.strictEqual(testItemWithParams.description, '');
});
test("test diff is not duplicated when failing assertion is extracted", () => {
const range = new Range(9, 0, 11, 0);
const testItem = generateTestItem(testController, 'junit@junit5.TestWithExtractedEqualityAssertion#test', TestKind.JUnit5, range, undefined, 'TestWithExtractedEqualityAssertion.java');
const testItem = generateTestItem(testController, 'junit@junit5.TestWithExtractedEqualityAssertion#test()', TestKind.JUnit5, range, undefined, 'TestWithExtractedEqualityAssertion.java');
const testRunRequest = new TestRunRequest([testItem], []);
const testRun = testController.createTestRun(testRunRequest);
const startedSpy = sinon.spy(testRun, 'started');

Просмотреть файл

@ -18,7 +18,7 @@ export function generateTestItem(testController: TestController, id: string, tes
const projectName = id.substring(0, id.indexOf('@'));
const fullName = id.substring(id.indexOf('@') + 1);
const label = id.substring(id.indexOf('#') + 1) + '()';
const label = testKind === TestKind.JUnit5 ? id : id.substring(id.indexOf('#') + 1) + '()';
const testItem = testController.createTestItem(id, label, Uri.file(uri));
testItem.range = range || new Range(0, 0, 0, 0);

Просмотреть файл

@ -47,6 +47,12 @@
<version>5.6.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>7.7.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

Просмотреть файл

@ -1,29 +1,35 @@
package junit4;
import static org.junit.Assert.assertEquals;
import java.util.Arrays;
import java.util.Collection;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;
import java.util.Arrays;
import java.util.Collection;
import static org.junit.Assert.assertEquals;
@RunWith(Parameterized.class)
public class ParameterizedTest {
private int input;
private int expected;
@Parameter
public int expected;
public ParameterizedTest(int input, int expected) {
this.input = input;
this.expected = expected;
}
@Parameters
public static Collection<Integer> data(){
return Arrays.asList(1, 2);
@Parameterized.Parameters
public static Collection<Object[]> data() {
return Arrays.asList(new Object[][] {
{ 0, 0 },
{ 1, 1 },
{ 2, 4 }
});
}
@Test
public void test() {
assertEquals(expected, 1);
public void testSquare() {
assertEquals(expected, input * input);
}
}

Просмотреть файл

@ -1,10 +1,25 @@
package junit5;
import static org.junit.jupiter.api.Assertions.fail;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
public class AppTest {
@Test
void testGetGreeting() {
}
@ParameterizedTest
@CsvSource({
"1, 2",
"1, 1"
})
public void testGetGreeting(int first, int second) throws Exception {
if (second == 2) {
fail("second should not be 2");
}
}
}

Просмотреть файл

@ -0,0 +1,32 @@
package testng;
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
public class CharUtilsTest {
@DataProvider
public Object[][] ValidDataProvider() {
return new Object[][] {
{ 'A', 65 }, { 'a', 97 },
{ 'B', 66 }, { 'b', 98 },
{ 'C', 67 }, { 'c', 99 },
{ 'D', 68 }, { 'd', 100 },
{ 'Z', 90 }, { 'z', 122 },
{ '1', 49 }, { '9', 517 }
};
}
@Test(dataProvider = "ValidDataProvider")
public void CharToASCIITest(final char character, final int ascii) {
int result = (int) character;
Assert.assertEquals(result, ascii);
}
@Test
public void CharToASCIITest() {
Assert.assertEquals(1, 2);
}
}