Just got the email about it. ReSharper 4.0 moved to a beta status. You can find the details here.
Personally, I have been using a fairly old build, with relatively few problems.
Just got the email about it. ReSharper 4.0 moved to a beta status. You can find the details here.
Personally, I have been using a fairly old build, with relatively few problems.
I saw several solution for extending NUnit and MbUnit to add new functionality, all of them were far too complex for me. I didn't want this complexity. Here is the entire code that I had to write in order to make xUnit integrate with my DSL:
public class DslFactAttribute : FactAttribute { private readonly string path; public DslFactAttribute(string path) { this.path = path; } protected override IEnumerable<ITestCommand> EnumerateTestCommands(MethodInfo method) { DslFactory dslFactory = new DslFactory(); dslFactory.Register<TestQuoteGeneratorBase>( new TestQuoteGenerationDslEngine()); TestQuoteGeneratorBase[] tests = dslFactory.CreateAll<TestQuoteGeneratorBase>(path); for(var test in tests) { Type dslType = test.GetType(); BindingFlags flags = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance; foreach (MethodInfo info in dslType .GetMethods(flags)) { if (info.Name.StartsWith("with")) yield return new DslRunnerTestCommand(dslType, info); } } } }
And the DslTestRunnerCommand:
public class DslRunnerTestCommand : ITestCommand { private readonly MethodInfo testToRun; private readonly Type dslType; public DslRunnerTestCommand(Type dslType, MethodInfo testToRun) { this.dslType = dslType; this.testToRun = testToRun; } public MethodResult Execute(object ignored) { object instance = Activator.CreateInstance(dslType); return new TestCommand(testToRun).Execute(instance); } public string Name { get { return testToRun.Name; } } }
That is what I am talking about when I am talking about easy extensibility.
Some of the things that I come up when I am doing this things are simply hilarious.
It start from this:
And moves to this:
I don't think that anyone can say that the naming of those unit tests are in any way misleading.
I just run into a road block, and I am posting before lunch, hopefully I'll get some ideas about how to solve this.
I have a directory full of source files, which contains tests. What I want to do is to write something like this:
public class MyTest { [ExecuteAllTestsIn("tests/validators")] public void Validators() { } }
The typical scenario for each source file is something like:
public void ExecuteSingleTest(string path) { var test = CompileAndGetInstance(path);
ExecuteTestInUnitTestingFramework(test); }
A source file can contain more than a single test, and I want all those individual tests to be reported as part of the overall test run.
The problem is that I took a look at the extensibility mechanisms for both NUnit and MbUnit, and they are so big. It is not that I can't see how I would solve the issue, but it would require a lot of work to do so.
I know how I can do this with xUnit, where it would be a truly trivial affair.
Am I missing something? I never really had to deal with the extensibility mechanisms in NUnit or MbUnit before.
Yesterday I asked how we can efficiently test this piece of code:
specification @vacations: requires @scheduling_work requires @external_connections
Trying to test that with C# code resulted in 1500% disparity in number of lines of code. Obviously a different approach was needed. Since I am in a DSL state of mind, I wrote a test DSL for this:
script "quotes/simple.boo"
with @vacations:
should_require @scheduling_work
should_require @external_connections
with @scheduling_work:
should_have_no_requirements
I like this.
You can take a look at the code here.
There is something that really bothers me when I want to test this code:
specification @vacations: requires @scheduling_work requires @external_connections
And I come up with this test:
[TestFixture] public class QuoteGenerationTest { private DslFactory dslFactory; [SetUp] public void SetUp() { dslFactory = new DslFactory(); dslFactory.Register<QuoteGeneratorRule>(new QuoteGenerationDslEngine()); } [Test] public void CanCompile() { QuoteGeneratorRule rule = dslFactory.Create<QuoteGeneratorRule>( @"Quotes/simple.boo", new RequirementsInformation(200, "vacations")); Assert.IsNotNull(rule); } [Test] public void WhenUsingVacations_SchedulingWork_And_ExternalConnections_AreRequired() { QuoteGeneratorRule rule = dslFactory.Create<QuoteGeneratorRule>( @"Quotes/simple.boo", new RequirementsInformation(200, "vacations")); rule.Evaluate(); SystemModule module = rule.Modules[0]; Assert.AreEqual("vacations", module.Name); Assert.AreEqual(2, module.Requirements.Count); Assert.AreEqual("scheduling_work", module.Requirements[0]); Assert.AreEqual("external_connections", module.Requirements[1]); } [Test] public void WhenUsingSchedulingWork_HasNoRequirements() { QuoteGeneratorRule rule = dslFactory.Create<QuoteGeneratorRule>( @"Quotes/simple.boo", new RequirementsInformation(200, "scheduling_work")); rule.Evaluate(); Assert.AreEqual(0, rule.Modules.Count); } }
I mean, I heard about disparity in number of lines, but I think that this is beyond ridiculous.
Martin Fowler talks about the almost instinctive rejection of external DSLs because writing parsers is hard. I agree with Fowler on that writing a parser to deal with a fairly simple grammar is not a big task, certainly there isn't anything to recommend XML for the task over an textual parser.
The problem that I have with external DSL is actually different. It is not the actual parsing that I object to, it is the processing that needs to be done on the parse tree (or the XML DOM) in order to get to an interesting result that I dislike.
My own preference is to utilize an existing language to build an internal DSL. This allows me to build on top of all the existing facilities, without having to deal with all the work that is required to get from the parse tree to a usable output.
In the case of the example that Fowler uses for his book (the state machine outlined here), the use of an internal DSL allows me to go from the DSL script to a fully populated semantic model without any intermediate steps. I give up some syntactic flexibility in exchange of not worrying about all the details in the middle.
The benefit of that is huge, which is why I would almost always recommend going with an internal DSL over building an external one. Here is a simple example, a business rule DSL:
suggest_preferred_customer: when not customer.IsPreferred and order.Total > 1000 apply_discount_of 5.precent: when customer.IsPreferred and order.Total > 1000
I wrote the code to use this DSL as a bonus DSL for my DSL talk in DevTeach. It took half an hour to forty five minutes, and it was at 4 AM. I extended this DSL during the talk to support new concepts and to demonstrate how easy it is.
I got to that point by leaning heavily on the host language to provide as much facilities as I could.
In short, it is not the parsing that I fear, it is all the other work associated with it.
For various reasons which will be made clear soon, I needed to write the same test twice, once using Rhino Mocks, the second time using hand rolled stubs. I thought it was an interesting exercise, since this is not demo level code.
[Test] public void WillCallHandlesWithWithRouteTestHanlderWhenRouteCalled_UsingRhinoMocks() { const IQuackFu msg = null; var mocks = new MockRepository(); var routing = dslFactory.Create<RoutingBase>(@"Routing\simple.boo"); var mockedRouting = (RoutingBase)mocks.PartialMock(routing.GetType()); Expect.Call(() => mockedRouting.HandleWith(null, null)) .Constraints(Is.Equal(typeof(RoutingTestHandler)), Is.Anything()); mocks.ReplayAll(); mockedRouting.Initialize(msg); mockedRouting.Route(); mocks.VerifyAll(); } [Test] public void WillCallHandlesWithWithRouteTestHanlderWhenRouteCalled() { const IQuackFu msg = null; dslFactory.Register<StubbedRoutingBase>(new StubbedRoutingDslEngine()); var routing = dslFactory.Create<StubbedRoutingBase>(@"Routing\simple.boo"); routing.Initialize(msg); routing.Route(); Assert.AreEqual(typeof (RoutingTestHandler), routing.HandlerType); Assert.IsInstanceOfType( typeof(NewOrderMessage), routing.Transformer() ); }
Eli Lopian joined the discussion about Mocks, Statics and the automatic rejection some people have of Type Mock and its capabilities.
Here is the deal.
Hm... that seems inconsistent of me...
Leaving aside the fact that I feel no urging need to be internally consistent, I don't have an issue with the feature itself. Mocking statics is not inherently bad. What I consider bad is the reliance of such a feature to write highly coupled code.
It is more an issue of guidance and form than a matter of actual features.
* Note that I said, "given a patch", the feature is not actually interesting enough for me to spend time implementing it.
D'Arcy has a post about teachers vs. speakers, which is a topic that came up a few times during DevTeach. My thoughts about this are fairly complex, but let me see if I can express them in a coherent fashion.
There is a definite difference between teaching and speaking. I like to think about speaking as a show that is targeted at increasing the knowledge of the audience on the subject at hand. Teaching is imparting that knowledge in an actionable form.
To take a concrete example, after my MonoRail talk, I don't expect anyone to be able to build a site using MonoRail. Certainly not with additional resources to go through. After my MonoRail course, however, I would consider this a personal failure if any of the participants wasn't able to build a site using MonoRail.
A success criteria for the MonoRail talk is that the audience groks the gestalt of MonoRail. They understand the tradeoffs in choosing it, what it would bring them and the overall model that is used.
Frankly, in the space of 60 to 75 minutes, I do not believe that you could do more.
Given those constraints, I do not think that you could do more than introduce a subject and open the mind of the people in the audience to why they should learn more about it.
Imparting knowledge takes time, far lower level of granularity when talking about how to do things, and a more gradual build up of the subject material. It takes much longer, since it is also requires a channel with much higher bandwidth for communication.
Unless the topic that I am talking about can be covered in a short span of time, when faced with the timing constraints of a typical speaking engagement, there is no other option than reverting to a lower-bandwidth, hit-the-high-notes, give-an-impression-not-complete-picture approach.
I like teaching, and I enjoy speaking, and I don't think that there should be a value judgement between them.
There are posts all the way to Jun 09, 2025