📜 ⬆️ ⬇️

Do you like Assert.That as some others love it or is dedicated to the release of NUnit v3 beta

Recently, the first beta version of the NUnit v3 test framework has been released. Among other things, this version implements the parallel execution of tests (almost out of the box). I decided to check how it works on one real project and found that the new version of nunit does not support some of the things used in previous versions. In particular, it is proposed to use Assert.Thorws or Assert.That instead of the ExpectedException attribute.
Regardless of the release of this beta, in one of the projects I started using the Assert.That model instead of all the other methods and attributes of nunit.

Under the cut a little experience transfer attribute ExpectedException model Assert.That.


As it turned out, the test project that I chose to translate under nunit v3. contains over 100 uses of the ExpectedException attribute. Naturally, I wanted to automate the transition process.
')
It is interesting that if earlier the attribute ExpectedException seemed very successful, recently I discovered several problems:
For example, in the following test it is not very clear in which line an exception is expected. Usually - in the latter, but if some previous method throws out the same exceptional situation, the test will not work correctly. In any case, there is some kind of uncertainty “where to expect an exceptional situation after all”.
[Test] [ExpectedException(typeof(ArgumentException))] public void TestExpectedException() { foo1(); foo4(); foo1(); } 


Another trifle that interferes is the “code coverage” reports, i.e. you start dotCover , study the report and see:



But replace with Assert.That and quite another thing: you get 100% coverage.



After I realized that changing with "hands" is too simple a way :), I decided to write a plug-in for the resharper, which helps to translate nunit constructions into the Assert.That model.

And I started with the ones I need to translate my test project.

At first everything was quite simple:
  [Test] [ExpectedException] public void TestShortExpectedException() { foo1(); foo2(); foo1(); } 

translated into
  [Test] public void TestShortExpectedException() { foo1(); Assert.That(foo2, Throws.Exception); foo1(); } 

A more complex example is the use of an anonymous method.
  [Test] [ExpectedException] public void TestExpectedExceptionWithExpressions() { double i = 2 + getNumber(); } 

  [Test] public void TestExpectedExceptionWithExpressions() { Assert.That(() => { double i = 2 + getNumber(); }, Throws.Exception); } 

Specific expected type required implementation Throws.TypeOf
  [Test] [ExpectedException(typeof(ArgumentException))] public void TestExpectedException() { foo1(); foo4(); foo1(); } 

  [Test] public void TestExpectedException() { foo1(); Assert.That(() => { foo4(); }, Throws.TypeOf<ArgumentException>()); foo1(); } 

The expected text of the message of exceptional situation (or in Russian “the message of execination”) required to add .And.Message
  [Test] [ExpectedException(typeof(NotImplementedException), ExpectedMessage = "customer message")] public void TestExpectedExceptionWithCustomerMessage() { foo4("customer message"); } 

  [Test] public void TestExpectedExceptionWithCustomerMessage() { Assert.That(() => { foo4("customer message"); }, Throws.TypeOf<NotImplementedException>().And.Message.EqualTo("customer message")); } 


Not all constructs are supported yet: for example, MathType will not be converted correctly.
  [Test] [ExpectedException(typeof(NotImplementedException), ExpectedMessage = "customer message", MatchType = MessageMatch.Contains)] public void TestExpectedExceptionWithCustomerMessage() { foo4("my customer message"); } 


Converting Assert.IsNullOrEmpty and Assert.IsNotNullOrEmpty constructs implemented without programming, but only through Custom Patterns .
Custom Patterns is a strong feature, but, apparently, in the case of complex designs, it is still not running smoothly.
Assert - the construction is simple and there were no problems:




The plugin is called "NUnit.That.Resharper.Plugin" and its beta version is available for download via Resharper - Manage Extensions.
Tested only on resharper-version 8.2.
Right now a small set of designs is being maintained .

Visually, the work of the plugin looks like this:

choose on the right line Replace


and you get the converted expression (the ExpectedException attribute is removed)



Conclusions :
- Assert. That seemed to me a rather attractive model;
- NUnit v3. still beta (be careful with the documentation!), but you can already start trying on test projects and prepare real ones;
- a complete cycle ( including tests and distribution ) of writing plugins for a resharper is not as difficult as it seemed, and can be used to solve not only “common”, but also local problems.

I would like to express special gratitude to the resharper team (and personally mezastel ), who helped to understand the development of plug-ins in particular. Resharper SDK allows you to create Visual Studio projects from templates, which greatly facilitates the work.

References:
- github project https://github.com/constructor-igor/NUnit.That.Resharper.Plugin
- NUnit.That.Resharper.Plugin plugin in the gallery https://resharper-plugins.jetbrains.com/packages/NUnit.That.Resharper_v8.Plugin/

Links to examples and documentation
- developer documentation for resharper ReSharper DevGuide ;
- post " Write a plugin for ReSharper - not so difficult "
- Agent Mulder plugin for ReSharper

Source: https://habr.com/ru/post/254289/


All Articles