MsTest, Nunit, MbUnit etc
Unit testing is now available in VS 2012 Express. In the paid-for SKUs, you can use other unit test frameworks, not just MSTest. For instance, NUnit, MbUnit and so on.
First, install an adapter via Extensions.
Then install the framework via Nuget- and start writing tests!
There's now only one, the Test Explorer. Most people only ever used the Test Results before, and Test Lists was unusable. It has a thin red or green bar (at last!), and simple splitting into Failed and Passed tests (now with timings).
There's a search with filters ("FullName: Domain.Tests.MyTest"). For solutions with large numbers of tests this might be awkward- I'd like to see more customization of the result tree (by project/folder or namespace), and more filters.
The results at the bottom of the window are summarized, but you can still click through to the test and stack.
There's a button to make every build (Ctl-Shift-B) also run the tests - "Run Tests After Build". Builds and test are run in the background so it doesn't stop you coding (well, my underpowered 32bit laptop is less responsive, but it's vastly better than previous versions of VS). Not so good if you include some integration tests, but nice nonetheless.
Unit tests support async tests. And code coverage (in Premium and Ultimate only) is much easier- no .testsettings, no having to select the dlls, just right click the tests (or add /enablecodecoverage on the vstest.console.exe command line).
You can't test private methods anymore (didn't use that anyway). You can't Generate Unit Tests from a method either. In VS2010 I used this a fair amount- I got a test project with the correct references, and the correct namespaces as well, even if the stub test it created normally had to be deleted and rewritten straight away. I'll miss that.
Of course, they broke something. I always use Ctl+R-T to run the current test. Well, I hold Ctl and type R then T. Which just doesn't work in VS2012. You have to hold Ctl and type R, then release Ctl and press T. The combination I used, which turns out to be Ctl R,Ctl T, isn't mapped in VS2012. You can remap it manually. Very annoying.
Microsoft.Fakes: Stubs and Shims
These are mocking classes, similar to Moq, NMock and RhinoMocks, and derived from the Pex Moles project. It's simpler than Moq: there's no "Setup(" or "Verify". It's also VS Ultimate only (not in Premium or Professional). Personally I much prefer to do simple manual stubs (implement an interface in the test project) than full mocking. Full mocks are powerful but you end up with loads of code setting up the tests (tight coupling), and they make it easy to add too many dependencies (just because you can test it doesn't mean you can forget all about the SRP).
Microsoft.Fakes isn't going to replace mocking frameworks (there's no behaviour verification). The shimming is very powerful (and dangerous), similar to TypeMock Isolator and other expensive tools.
To add Fakes, right click the references.
You'll get a reference to Microsoft.QualityTools.Testing.Fakes and a project folder called Fakes with an xml file in it. For example, in a web application, you'll probably want to fake System.Web so you handle all the HttpContext/ Request stuff.
Stubs are simple (MSDN). Let's stub our input object and initialize it's value. All properties are automatically prepared to return the defaults (0s or nulls). The stub method (in the .Net framework or a local assembly) has a "Stub" prefix.
public void Test20()
var entity = new ClassLibrary1.Tasks.Fakes.StubEntity();
entity.Value = 20;
var processor = new Processor();
var result = processor.Execute(entity);
Shims are more difficult and powerful (MSDN).
Here's a method we want to test:
public class FileReader
public string ReadAllText(string path)
Here's how we can test it. Here we have to fake the System reference (which includes mscorlib). Note for shims, we have to have a ShimsContext. The prefix is "Shim" and methods and properties are prepared with lambda functions.
public void ReadAllTextTest()
var reader = new FileReader();
System.IO.Fakes.ShimFile.ReadAllTextString = (arg) => "x";
result = reader.ReadAllText(@"X:\doesnotexist\notThere.txt");