This project is read-only.

method formatting

Mar 6, 2010 at 6:46 AM
Edited Mar 6, 2010 at 6:55 AM

Hello guys,

I think you guys have had a great idea with StoryQ. It is forcing me to think about the specification first and behavior first and everything about this phase is under a manageable framework. In addition, the unit testing code become much more readable. Thank you for creating this project and share with the community.

My question is related to the method formatting. I understand the "underscore" rule and how a method name is converted in the narrative. However, sometimes I found it is limiting the way to describe my idea. For example, it seems hard to add shorthands like "HDD" in the method name--it gets converted to "h d d" in the narrative. And generally, all words in the narrative starts with a lower case letter. I suggest to change the formatting so that one can write a method like:

Create_HDD_test_for_Disk_Arg1_with_write size_of_Arg2MB(1, 4)  => "Create HDD test for Disk 1 with write size of 4MB"

Note all the necessary uppercase letters are preserved. "Arg1" and "Arg2" are preserved words.

I know it might be a violation of microsoft's C# naming convertions, but IMHO, readability is a far more important concern than naming conventions.

Please comment.

 

Mar 6, 2010 at 9:33 AM
Edited Mar 6, 2010 at 9:34 AM

Hi BnA!

in fact, RobertBeal had the same question (on twitter). You can override the way StoryQ formats a method by applying a MethodFormatAttribute to each method. The following one should give you the results you want:

 

public class UnderscoreMethodFormatAttribute : MethodFormatAttribute
    {
        /// <summary>
        /// Formats a method by putting parameters inline
        /// </summary>
        /// <param name="method">The method to describe</param>
        /// <param name="parameters">the parameters currently being passed to the method</param>
        /// <returns></returns>
        public override string Format(MethodInfo method, IEnumerable<string> parameters)
        {
            var argStrings = new List<string>(parameters);
            string s = method.Name.Replace('_', ' ');
            for (int i = 0; i < argStrings.Count; i++)
            {
                s = s.Replace("Arg" + (i + 1), argStrings[i]);
            }
            return s;
        }
    }

I will work on a way to allow you to tell StoryQ what the default MethodFormatter should be, so that you don't have to apply this everywhere if you adopt and alternative naming convention...

 

Mar 6, 2010 at 3:41 PM

Hello robfe,

I've got it working by replacing the current formatter with the above code. Thanks!

There is one bit of trick I have to play. That is to add at least one underscore somewhere in the method name. But this is a boundary case anyway.

Nice job!

 

Mar 6, 2010 at 3:48 PM

Could you use double underscore to represent an actual underscore?

 

string s = method.Name.Replace("__", "!").Replace('_', ' ').Replace('!', '_');

! could obviously be any special placeholder that isn't a valid char in a method name...

 

Mar 6, 2010 at 3:57 PM
Edited Mar 6, 2010 at 3:58 PM

I'm looking at using When_the_user_is_X_years_old(int age), or When_the_user_is_XageX_years_old(int age)

Started writing it with some tests. Been messing around with the code, looking for a nice way that you can specify settings rather than it trying to work out which formatter to use.

And yeah StyleCop will moan about it, but I just disable the rule.

Mar 6, 2010 at 5:01 PM

Robert B,

I was thinking of adding a static class to StoryQ called StoryQSettings with a few properties on it.

One of these would be a Func<MethodInfo, MethodFormatter>. By default, it would be a function that does what storyQ already does, but you could override that func to always return your specific underscore formatter.

This is in fact what ExceptionHelper already does to let you override the default way of "pending" a test. I would probably move ExceptionHelper's Func<Exception, string, Exception> into StoryQSettings too...

Thoughts?

Mar 6, 2010 at 5:17 PM

Ah cool, yeah that's what I've done, although I've just quickly set a property

namespace StoryQ.Tests.Formatting
{
[TestFixture]
public class UnderscoreFormatterTests
{
[TestFixtureSetUp]
public void TestFixtureSetup()
{
Settings.MethodFormatAttribute = new UnderscoreMethodFormatAttribute();
}

[Test]
public void When_a_method_has_underscores_and_no_parameters()
{
Action action = Method_with_underscores_and_no_parameters;
Assert.AreEqual("Method with underscores and no parameters", Formatter.FormatMethod(action));
}

[Test]
public void When_a_method_has_underscores_and_multiple_parameters()
{
Action<string, int> action = Method_for_X_with_underscores_and_X_parameters;
Assert.AreEqual("Method for testing with underscores and 2 parameters", Formatter.FormatMethod(action, "testing", 2));
}

private static void Method_with_underscores_and_no_parameters()
{
}

private static void Method_for_X_with_underscores_and_X_parameters(string reason, int paramters)
{
}
}

public class UnderscoreMethodFormatAttribute : MethodFormatAttribute
{
public override string Format(MethodInfo method, IEnumerable<string> parameters)
{
var args = new Queue<string>(parameters);

return Regex
.Replace(method.Name, "_X_", x => "_" + args.Dequeue() + "_")
.Replace("_", " ");
}
}
}


And inside the formatter I made the change:

        private static MethodFormatAttribute GetFormatter()
{
var formatter = new ParametersInlineMethodFormatAttribute() as MethodFormatAttribute;

if (Settings.MethodFormatAttribute != null)
{
formatter = Settings.MethodFormatAttribute;
}

return formatter;
}

Using a static settings is a little bit of a pain in the tests, just a matter of separating them out into different classes to represent each context

for (int i = 0; i < argStrings.Count; i++)
{
s = s.Replace("Arg" + (i + 1), argStrings[i]);
}
Mar 7, 2010 at 5:34 PM

Ok i've commited the change into hg - it's not part of a release yet, but if you build from source you'll get the ability to set StoryQSettings.DefaultMethodFormatSelector to "x=>new UnderscoreMethodFormatAttribute()"

let me know how that works out, if it meets your needs I'll think about releasing it...

Cheers - Rob

Mar 7, 2010 at 5:49 PM

Ah cool. Name the formatter differently if you want was just something I quickly came up with. Looks good though, thanks for the change.

Mar 7, 2010 at 6:00 PM

I haven't added the UnderscoreMethodFormatAttribute to storyQ yet, actually, am still thinking about argument placeholders for that one. But it is now easy to slot your own one in!