You use a convention!
public class StringPropertyConvention : IPropertyConvention, IPropertyConventionAcceptance
{
public void Apply(IPropertyInstance instance)
{
instance.Length(4001);
}
public void Accept(IAcceptanceCriteria<IPropertyInspector> criteria)
{
criteria.Expect(x => x.Property.PropertyType == typeof (string));
}
}
Make sure you register the conventions with the automapper.
Peace
Time and time again I encounter repositories which are just a free-for-all mess, so here is a definitive guide to SVN and project code organisation for the tidy-inept.
Most people will use their repository for multiple projects. For this reason it is a sensible idea to have top level folders which semantically group your code. How you do this depends largely on what code/projects you have in SVN. Here’s an example:
root
- Customer A
-- Project X
-- Project Y
- Customer B
-- Project Q
-- Project X
Next, under each Project you should have:
Project X
- trunk
- branches
- releases
- tags
Sometimes its more appropriate to have the releases folder under branches (as they technically are branches), it doesn’t really matter. What is important is that you are branching your releases!
.NET Project Organisation
Here is how I organise my projects:
/
/lib
/src
/src/<projectname>.sln
/src/<projectname><assembly-specific-names>
/tools
/rakefile.rb
Nice and clean
The lib folder holds all your 3rd party assemblies which your project utilises.
The src folder contains…you guessed it, your source code!
The tools folder contains mainly build tools and test runners. Mine also has the NHibernate Profiler in there, too.
The rakefile is my build script, if you enjoy angled-bracketed-unneccessaryness this could be your NAnt or MSBuild file.
Next, externals. If your project shares code with another, this shared code should be under a separate project, and included via an svn:external under the lib folder. For example:
/lib/<folder-for-external>
Useful Resources
Here are some great examples of best practices for code and svn organisation.
And here is an excellent book on the subject!
One tidy life….Done!
Following on from my recent post how to test asp.net mvc views existence, I found myself with in a very similar situation! This time however, it was FileResult instead of ViewResult.
I’m not making any excuses, this is far from the prettiest or most flexible solution, but for my setup it works perfectly
Have some code:
public abstract class ControllerTest<TController> where TController : IController
{
protected void AssertFileIsCorrectAndExists(FileResult result, string filename)
{
// hack of death!!!!
var webProjectPath = Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, Path.Combine("../../../", typeof(TController).Assembly.GetName().Name)));
// crudely trim leading ~/
if (filename.StartsWith("~/"))
filename = filename.Substring(2);
var fullPath = Path.Combine(webProjectPath, filename);
Assert.IsTrue(File.Exists(fullPath), "File `" + fullPath + "` does not exist");
}
Following a recent embarrassing episode where I had been banging on about how unit testing saves the world, then released a broken site, I decided a solution to prevent this happening again was necessary!
I currently test my MVC ViewResults like this:
public class when_requesting_a_login_form : ControllerTest<LoginController>
{
private ViewResult result;
protected override void Act()
{
this.result = this.SubjectUnderTest.LogIn() as ViewResult;
}
[Test]
public void the_login_view_should_be_returned()
{
this.result.ViewName.ShouldEqual("Login");
}
}
However this doesn’t check that the Login.aspx view actually exists (which it didn’t in the case I’m talking about, as I only found out at runtime). Below is my new test:
[Test]
public void the_login_view_should_be_returned()
{
AssertViewIsCorrectAndExists(result, "Login");
}
This assertion not only checks that the view names match, but also that the file exists on disc.
The solution is far from elegant, but it works, which is better than nothing!
Before I show you the codes, some prerequisite knowledge about my solution setup is required.
My folders are ALWAYS organised like this:
/src/Project.Web/
/src/Project.Domain/
/src/Project.Tests.Unit/
with these folder names matching the assembly names. This allows the following very fragile code to work:
protected void AssertViewIsCorrectAndExists(ViewResult result, string viewName)
{
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new TestingViewEngine());
Assert.AreEqual(viewName, result.ViewName, "View names do not match");
var controllerContext = Stub<ControllerContext>();
controllerContext.RouteData = new RouteData();
controllerContext.Controller = SubjectUnderTest;
var controllerName = typeof(TController).Name;
controllerContext.RouteData.Values.Add("controller", controllerName.Substring(0, controllerName.Length - "controller".Length));
var viewEngineResult = result.ViewEngineCollection.FindView(controllerContext, result.ViewName, result.MasterName);
Assert.IsNotNull(viewEngineResult.View, "View '" + result.ViewName + "' could not be found");
}
public class TestingViewEngine : WebFormViewEngine
{
public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
{
// hack of death!!!!
var webProjectPath = Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, Path.Combine("../../../", controllerContext.Controller.GetType().Assembly.GetName().Name)));
foreach(var location in this.ViewLocationFormats)
{
var virtualViewPath = string.Format(location, viewName, controllerContext.RouteData.Values["controller"]);
// crudely trim leading ~/
virtualViewPath = virtualViewPath.Substring(2);
var fullPath = Path.Combine(webProjectPath, virtualViewPath);
if (File.Exists(fullPath))
return new ViewEngineResult(MockRepository.GenerateStub<IView>(), this);
}
return new ViewEngineResult(this.ViewLocationFormats);
}
}
Crude I know, but I hope this helps someone!
Ok this was an annoying one, If your TDD.Net runner keeps telling you “No tests run (No tests where found)” and you’ve run the “InstallTDNetRunner.bat” you can try the following:
Edit the InstallTDNetRunner.bat
and comment out the last 2 lines:
regedit MSpecTDNet.reg
del MSpecTDNet.reg
Run the bat file and a .reg should appear in the same folder. Edit this.
in there you should see: AssemblyPath”=”<some path>\\Machine.Specifications.TDNetRunner.dll”
Make sure this path is actually correct (it wasnt for me). Then save the .reg and run it.
Job done
Just a quick one, but it took me a while to figure this out. Hopefully this can help someone else out.
To get MSpec working with ReSharper you need to copy all the MSpec dlls into the resharper’s plugins folder, so you end up with:
ReSharper/bin/plugins/machine.specifications/<dlls here>
Make sure you delete whichever one of the ReSharperRunner dlls is not your ReSharper version!
Enjoy