Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prettify Test Method Display Name #644

Closed
wants to merge 5 commits into from

Conversation

ahmedalejo
Copy link

@ahmedalejo ahmedalejo commented Sep 26, 2019

Friendly "Display Name" for test method names

[TestMethod]
void Method_names_should_be_readable_when_hinted()
{
}

"Method_names_should_be_readable_when_hinted" => "Method names should be readable when hinted"


[TestMethod]
void Say_What_You_Have_Spaces_in_Your_CSharp_Test_Names()
{
}

"Say_What_You_Have_Spaces_in_Your_CSharp_Test_Names" => "Say What You Have Spaces in Your CSharp Test Names"

similar to

image

Complements #466

This spec can be improved for other cases PascalCase, CamelCase.
and specified DisplayName should be favoured

Friendly "Display Name" for test method names 

"Method_names_should_be_readable_when_hinted" => "Method names should be readable when hinted"
@msftclas
Copy link

msftclas commented Sep 26, 2019

CLA assistant check
All CLA requirements met.

TestMethod.cs(47,1): error SA1028: Code must not contain trailing whitespace 
TestMethod.cs(52,1): error SA1028: Code must not contain trailing whitespace 
TestMethod.cs(111,1): error SA1028: Code must not contain trailing whitespace
TestMethod.cs(42,32): error SA1101: Prefix local calls with this
TestMethod.cs(112,16): error SA1400: Element 'GetFriendlyName' must declare an access modifier
TestMethod.cs(42,32): error SA1101: Prefix local calls with this
@ahmedalejo ahmedalejo changed the title Pretify Test Method Display Name Prettify Test Method Display Name Oct 3, 2019
@ahmedalejo
Copy link
Author

ahmedalejo commented Oct 3, 2019

There´s also been other specs #515
and [Proposal Support Automatic "Pretty" Display Name for Test Cases] by xunit/xunit#759

@spottedmahn
Copy link
Contributor

I love this idea. I was thinking about this same topic.

  • How do we "fix" all of the existing test names? I'm thinking a lot of test method names are written in PascalCase.
  • Do method names matter anymore? What conventions should we be using if using TestMethod(displayName: "Some name")?
[TestMethod("Now I can read my test names like a human not a computer 😜")]
public void Blah1()
{
}

@ahmedalejo
Copy link
Author

ahmedalejo commented Dec 18, 2019

@spottedmahn

It can be done via two steps

  1. Add the string DisplayName property to the TestMethodAttribute
  2. Add a string GetDisplayName(System.Reflection.MethodInfo ) that is extensible and by default returns the method name and returns DisplayName if not empty
[TestMethod("Consecutive authentication attempts with invalid credentials should fail")]
public void MyTest()
{ ... }
//or

[MyAppTestMethod]
public void Consecutive_authentication_attempts_with_invalid_credentials_should_fail()
{ ... }

//Given the following definitions
public class TestMethodAttrubte : Attribute
{
    public string DisplayName { get; set; }

    public virtual string GetDisplayName(System.Reflection.MethodInfo methodInfo) =>
        string.IsNullOrWhiteSpace(this.DisplayName) 
        ? methodInfo.Name 
        : this.DisplayName?.Trim();

   ...
}

public class MyAppsTestMethodAttrubte : TestMethodAttrubte
{
    public override string GetDisplayName(MethodInfo methodInfo) =>
        methodInfo
            .Name
            .Replace("_", " ")
            .Replace(".", ", ");
}

@nohwnd
Copy link
Member

nohwnd commented Dec 20, 2019

I like the general idea, and the extension point. But looking at the xunit spec, and the amount of work and iteration they did on it, I am inclined to keep the implementation at just that. No built in automatic rewrites.

That way you can provide your own implementation, which can be simple enough to cover just the conventions you use. This would get the change merged quicker because we will not have to provide a good generic implementation, and multiple configuration options to cater every possible edge case.

@nohwnd nohwnd self-assigned this Dec 20, 2019
Copy link

@sebainones sebainones left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've seen all 5 commits and reviewed the 'files changed".
In my opinion, it's good but I don't know If I need an specific role in order to Approve this Pull Request.
@nohwnd apologies for the newbie question but : is there any formal procedure (documentation) that I should follow in order to Approve this PR or should I just hit the button? ;)

Copy link

@sebainones sebainones left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't found any Unit Test for this change.
It could be added something like this:

 [TestClass]
    public class TestMethodTest
    {
        [TestMethod]
        public void TestMethodTestConstructorWithTestNameWithUnderscoreShouldReturnReadbleDisplayName()
        {
            MSTest.TestAdapter.ObjectModel.TestMethod testMethod = new MSTest.TestAdapter.ObjectModel.TestMethod("Dummy_Test_Name", "dummyClassName", "dummyAssemblyName", false);

            Assert.AreEqual("Dummy Test Name", testMethod.DisplayName);
        }
    }

@spottedmahn
Copy link
Contributor

Java JUnit 5 Display Name Generators

#interesting 🤔

@nohwnd
Copy link
Member

nohwnd commented Mar 6, 2020

@spottedmahn could you elaborate a bit more on why you find that interesting? 🙂 as I read it it is basically the same concept as here, or am I missing something important?

@ahmedalejo
Copy link
Author

Hi guys

cc: @spottedmahn

I plan to close this PR. I prefer sending in one that satisfies the below use case.

What do you think as the following partially implemented this.
#410 issue
#466 PR

[TestMethod("Consecutive authentication attempts with invalid credentials should fail")]
public void MyTest()
{ ... }
//or

[MyAppTestMethod]
public void Consecutive_authentication_attempts_with_invalid_credentials_should_fail()
{ ... }

//Given the following definitions
public class TestMethodAttrubte : Attribute
{
    public string DisplayName { get; set; }

    public virtual string GetDisplayName(System.Reflection.MethodInfo methodInfo) =>
        string.IsNullOrWhiteSpace(this.DisplayName) 
        ? methodInfo.Name 
        : this.DisplayName.Trim();

   ...
}

public class MyAppsTestMethodAttrubte : TestMethodAttrubte
{
    public override string GetDisplayName(MethodInfo methodInfo) =>
        methodInfo
            .Name
            .Replace("_", " ")
            .Replace(".", ", ");
}
public class MyHappyAppsTestMethodAttrubte : MyAppsTestMethodAttrubte 
{
    public override string GetDisplayName(MethodInfo methodInfo) =>
        base.GetDisplayName(methodInfo)
            .Replace("fails", "😢")
            .Replace("should succeed", "😅");
}

@spottedmahn
Copy link
Contributor

🙂 as I read it it is basically the same concept as here

Yep, seems like it. It was interesting to me that another "team" came to the same "discovery" independently.

There might also be some ideas in their approach we could learn from

@ahmedalejo
Copy link
Author

@nohwnd I missing something important?
The main thing is that there is more traction in other libraries about this topic. Basically, they´ve implemented it one way or the other.
It's a common need that we have to pull off for testfx

@ahmedalejo
Copy link
Author

ahmedalejo commented May 1, 2020

@spottedmahn @nohwnd

Found a better extension point that could be baked into TestMethodAttribute with ease.

The below is what i´m currently using

cheers.

public class PrettyTestClassAttribute : TestClassAttribute
{
    public override TestMethodAttribute GetTestMethodAttribute(TestMethodAttribute wrappedTestMethodAttribute)
    {
        var attribute = base.GetTestMethodAttribute(wrappedTestMethodAttribute);

        return attribute is PrettyTestMethodAttribute
            ? attribute
            : new PrettyTestMethodAttribute(attribute);
    }
}

public class PrettyTestMethodAttribute : TestMethodAttribute
{
    private readonly TestMethodAttribute wrappedTestMethodAttribute;

    public PrettyTestMethodAttribute(){ }

    public PrettyTestMethodAttribute(TestMethodAttribute wrappedTestMethodAttribute) =>
        this.wrappedTestMethodAttribute = wrappedTestMethodAttribute;

    public override TestResult[] Execute(ITestMethod testMethod)
    {
        TestResult[] results;

        if (wrappedTestMethodAttribute is null)
            results = base.Execute(testMethod);
        else
            results = wrappedTestMethodAttribute.Execute(testMethod);

        if(results.Any())
            results[0].DisplayName = testMethod.TestMethodName
                .Replace("_eq_", " == ")
                .Replace("_neq_", " != ")
                .Replace("_gt_", " > ")
                .Replace("_gte_", " >= ")
                .Replace("_lt_", " < ")
                .Replace("_lte_", " <= ")
                .Replace("Bug_", "🐞");
        return results;
    }
}

Hopefully will create a new pull request suggesting to bake this into TestMethodAttribute

@ahmedalejo ahmedalejo closed this May 1, 2020
This was referenced May 1, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants