⬆️ ⬇️

Microsoft Moles

Moles is a lightweight tool from MS Research that can automatically generate stubs for interfaces and virtual methods, as well as sealed classes, non-virtual and static methods (!), By generating code that you can later slip on the desired delegate called instead of a specific method . The first type of plugs is called stubs (stubs), and the second - moles (moles). This is the thing I used to test asynchronous operations, which I mentioned earlier , but let's get everything in order.



Stubs





Let's look at this example. Suppose that we understand the value of unit tests, as well as such principles as Dependency Inversion, and other insanely useful principles and patterns (maybe all other SOLID principles, and maybe even FIRST ). And the point is not that we are fans of tests or Uncle Bob, but simply because we know that high connectivity is bad. Therefore, we try to reduce dependencies within reasonable limits by allocating interfaces and then “injecting” them into the class constructors or into the methods by which these interfaces are necessary to perform their tasks.

')



So let's assume that for some abstraction in our code, we have allocated the IFoo interface and created some class that uses this interface.



namespace PlayingWithMoles

{

// , -

public interface IFoo

{

string SomeMethod();

}

// - , IFoo

public class FooConsumer

{

// ""

public FooConsumer(IFoo foo)

{

this .foo = foo;

}

// , - IFoo

public void DoStuff()

{

var someResults = foo.SomeMethod();

Console .WriteLine( "Doing stuff. IFoo.SomeMethod results: {0}" , someResults);

}

private readonly IFoo foo;

}

}




* This source code was highlighted with Source Code Highlighter .




Now, suppose that our bright minds were visited by a no less bright idea, and not to write a unit test of the wonderful class FooConsumer , with the equally remarkable DoStuff method (it is clear that the meaning in testing such code is approximately zero, but you understood the idea) . So, to create an instance of the FooConsumer class, you need to find an implementation of the IFoo interface, which may be in our code, but not the fact that it is suitable for unit tests, because it can be difficult (or impossible) to use it, because this class may depend on another class that depends on the third and so on. Of course, such a trifle of our brother can not stop, and if we took up the testing, we will definitely bring the matter to the end. Therefore, we will take and implement the interface with our hands, since the method is only one, and this will not cause any difficulties, with the result that we will get a test like this:



[TestClass()]

public class FooConsumerTest

{

class FooTester : IFoo

{

public string SomeMethod()

{

return "Test string" ;

}

}

[TestMethod]

public void DoStuffTest()

{

IFoo foo = new FooTester();

FooConsumer target = new FooConsumer(foo);

target.DoStuff();

}

}




* This source code was highlighted with Source Code Highlighter .




Now you can run this code and see in the Output window: Doing stuff. IFoo.SomeMethod results: Hello, Custom stub . Yes, it was not difficult, but we all know that the problems of real applications lie in the details and that in practice we are faced with much more complex interfaces than this and the implementation of each interface can hardly be called the most interesting in the world of work.



So, the Moles library. Creating stubs by this tool is as follows. In a project with tests, just right-click on the assembly with the business logic you want to test and select “Add Moles to Assembly”, after which the file “MyAssemblyName.moles” will be added to the project, and after compiling this project into The list of connected assemblies will display the assembly MyAssemblyName.Moles, which will contain all the generated stubs. Then this tool will automatically track successful builds with business logic and will automatically regenerate the stubs. The MyAssemblyName.moles file is a simple xml file in a specific format that specifies the name of the assembly for which stubs will be generated, as well as some parameters for their generation (for example, you can specify for which types of stubs, stubs or moles) and more).





NOTE

Starting with version 0.94, the moles file scheme has changed. Prior to this, you could cancel the automatic compilation of stubs, set Compilation = false in one of the sections of the configuration file, which caused the assembly with stubs not to be generated, but instead the generated file was directly added to the current project. Starting from version 0.94, this possibility has disappeared, but you can still see what the generated code looks like, rummaging through the subfolders of your project. For example, the current version of this tool saves the generated files in the following location: MyTestProject \ obj \ Debug \ Moles \ sl \ mgsl.



Let's look at a simplified version of the code generated for us by this tool:



namespace PlayingWithMoles.Moles

{

public class SIFoo

: Microsoft.Moles.Framework.Stubs.StubBase

, IFoo

{

string IFoo.SomeMethod()

{

var sh = this .SomeMethod;

if (sh != null )

return sh.Invoke();

else

{

// Behavior-,

}

}

// Sets the stub of IFoo.SomeMethod

public Func< string > SomeMethod;

}

}




* This source code was highlighted with Source Code Highlighter .




So, the generated class explicitly implements the source interface and contains delegates whose types correspond to the signature of the corresponding methods. Since our method takes no parameters and returns string , the stub contains a delegate of type Func <string> (that is, a delegate that returns a type of string and does not accept any parameters). Further, in the SomeMethod method, this delegate is simply called (if this delegate is null , then the StubNotImplementedException exception will be thrown by default , but this behavior can be changed). Notice that the class name of the stub is: S InterfaceOrClassName, and it is in the OriginalNamespace .Moles namespace .



Now let's change our initial test and use the stub generated for us:

[TestMethod]

public void DoStuffTestWithStubs()

{

var fooStub = new PlayingWithMoles.Moles.SIFoo();

fooStub.SomeMethod = () => "Hello, Stub!" ;

var target = new FooConsumer(fooStub);

target.DoStuff();

}




* This source code was highlighted with Source Code Highlighter .




Running it, we, as expected, see the following line: Doing stuff. IFoo.SomeMethod results: Hello, Moles Stub!



Once again, stubs are generated only for interfaces and virtual (non-sealed) methods of non-sealed classes. And there is no magic here, since for this, heirs classes or classes that implement your interfaces are generated, and call dispatching takes place at the expense of good old virtual calls. Yes, this thing is very interesting and allows you to save some time, but there is nothing surprising in it, unlike ... moles.



Moles





Moles are the second type of plugs, which is designed for the same purposes as stubs, but it can work with static or instance and non-virtual methods. Let's assume that our FooConsumer class is not tied to an IFoo interface, but to a specific Foo class that does not contain virtual methods:



namespace PlayingWithMoles

{

// Foo,

// , IFoo

public class Foo

{

public string SomeMethod()

{

return "Hello, from non-virtual method." ;

}

}

// - , Foo

public class FooConsumer

{

// Foo

public FooConsumer(Foo foo)

{

this .foo = foo;

}

// , - Foo

public void DoStuff()

{

var someResults = foo.SomeMethod();

Console .WriteLine( "Doing stuff. Foo.SomeMethod results: {0}" ,

someResults);

}



private readonly Foo foo;

}

}




* This source code was highlighted with Source Code Highlighter .




It is clear that if we have the opportunity to refactor this code and highlight the IFoo interface, then this is what should be done, but sometimes it may not be advisable, and sometimes even impossible. It often happens that we get someone else's code, which we need to unleash the coils of dependencies gradually, and tests are needed now; Yes, and not rare cases when this code is simply impossible to change, because you do not control it; After all, it may well be a third-party library or access to external resources, testing the availability of which is not part of your intentions.



This is where the second type of plugs that can be generated by this tool - moles will help. Moles are generated in a similar way and are located in the same nested namespace (OriginalNamespace .Moles ), however, they contain the prefix M instead of the prefix S , but instead of virtual methods and interfaces we can set the behavior of non-virtual static methods. To implement this behavior, the Moles library uses the CLR Profiler, in particular, it processes the callback function ICorProfilerCallback :: JITCompilationStarted in which, instead of the original method, it is pushed by our delegate. As a result, when calling the original method, the code fragment provided by us will be called.



Thus, in our case, the class PlayingWithMoles will be generated. Moles.M Foo, and let's see how you can test the good old (and most importantly useful) DoStuff method of the new version of the FooConsumer class:



[TestMethod]

[HostType( "Moles" )]

public void DoStuffTestWithMoles()

{

var fooMole = new PlayingWithMoles.Moles.MFoo();

fooMole.SomeMethod = () => "Hello, Mole!" ;

var target = new FooConsumer(fooMole);

target.DoStuff();

}




* This source code was highlighted with Source Code Highlighter .




Pay attention to the [HostType (“Moles”)] attribute, without which all the magic of the particles will stop working, because, as mentioned earlier, code “instrumentation” and the CLR Profiler are used for their work. This test is no more complicated than the previous one, in which stubs were used, and when we start we get exactly the result that we expect: Doing stuff. IFoo.SomeMethod results: Hello, Mole!



Now let's look at a more interesting example. In several previous posts I looked at different ways of dancing with tambourines around asynchronous operations, and as examples I used asynchronous retrieval of the content of web pages. But since I sometimes needed to work on a computer without access to the Internet, and every time I didn’t want to rewrite the examples, I had an idea to use this tool. In addition, a good rule of unit testing is decoupling from external resources (such as files, network connections, database), since otherwise these tests will no longer be modular, but will be integration tests. I do not say that integration tests are bad, no, this is good, but in modular tests we can focus on our code, while integration tests require the presence and normal operation of these external resources.



Let's assume that we have some WebRequestor class that accesses a web page and displays the length of the response received:



public class WebRequester

{

public void RequestWebPage( string url)

{

var request = WebRequest.Create(url);

var response = request.GetResponse();

Console .WriteLine( "Sync version. URL: {0}, Response content length: {1}" ,

url, response.ContentLength);

}

}




* This source code was highlighted with Source Code Highlighter .




Before we start writing tests, we need to generate moles for the WebRequest class . To do this, in the test project it is enough to right-click on the System assembly (since this class is located in it), select the “Add Moles Assembly” menu item, then recompile the project with tests, which will result in the System.Behaviors.dll assembly. , with all the necessary stubs and moles of the original System.dll assembly.



Now let's see how we can test our code:



[TestMethod]

[HostType( "Moles" )]

public void RequestWebPageTest()

{

var mole = new System.Net.Moles.MHttpWebResponse();

mole.ContentLengthGet = () => 5;

// URL-.

// , :

//System.Net.Moles.MHttpWebRequest.AllInstances.GetResponse = (r) =>

// {

// if (r.RequestUri == new Uri("http://rsdn.ru"))

// return mole;

// return r.GetResponse();

// };

//

System.Net.Moles.MHttpWebRequest.AllInstances.GetResponse = (r) => mole;

WebRequester target = new WebRequester();

target.RequestWebPage( "http://rsdn.ru" );

}




* This source code was highlighted with Source Code Highlighter .




In this test, first we create a stub for the HttpWebResponse class located in the System.Net .Moles namespace with the name M HttpWebRespoonse, and as a “body” of the ContentLength property we slip our lambda returning 5 . Now we “change” the GetResponse method for all instances of the HttpWebRequest class by setting the GetResponse delegate. After that, we can safely call the RequestWebPage method of the WebRequester class and get a normal result, even without access to the Internet: Sync version. URL: rsdn.ru , Response content length: 5.



Now let's go to the asynchronous version of getting the content of a web page, the RequestWebPageAsync method of the WebRequester class :



public void RequestWebPageAsync( string url)

{

var waiter = new ManualResetEvent( false );

var request = WebRequest.Create(url);

request.BeginGetResponse(

ar=>

{

var response = request.EndGetResponse(ar);

Console .WriteLine( "Async version. URL: {0}, Response content length: {1}" ,

url, response.ContentLength);

waiter.Set();

}, null );



waiter.WaitOne();

}




* This source code was highlighted with Source Code Highlighter .




For test purposes, I don’t want the method to complete control until the asynchronous operation is complete. In this code, we cannot use AsyncResult.AsyncWaitHandle , returned by the BeginGetResponse method, since the RequestWebPageAsync method can continue execution before calling the request.EndGetResponse method. As a result of this, there is no point in such “asynchronous”, but this is not important, because here I just want to show the mechanism for testing asynchronous operations and nothing more. But I think the idea is clear.



So now the test method:



[TestMethod]

[HostType( "Moles" )]

public void RequestWebPageAsyncTest()

{

var mole = new System.Net.Moles.MHttpWebResponse();

mole.ContentLengthGet = () => 5;

// ,

//

Action action = () => Thread.Sleep(500);



// , ,

//

// - (-,

// ).

ThreadPool.SetMinThreads(3, 3);

System.Net.Moles.MHttpWebRequest.AllInstances.BeginGetResponseAsyncCallbackObject =

(r, a, iar) => action.BeginInvoke(a, iar);

System.Net.Moles.MHttpWebRequest.AllInstances.EndGetResponseIAsyncResult =

(r, iar) => { action.EndInvoke(iar); return mole; };

WebRequester target = new WebRequester();

target.RequestWebPageAsync(http: //rsdn.ru);

}




* This source code was highlighted with Source Code Highlighter .




In our test method, we again create a stub M HttpWebResponse, an instance of which will return 5 when accessing the ContentLength property, and use the delegate that calls Thread.Sleep (500) to simulate a long-running operation. By running this test for execution, we get: Async version. URL: rsdn.ru , Response content length: 5. What was required to prove!



Instead of conclusion





The Moles library is a very interesting tool that will help you in generating simple stubs for your interfaces, and it will allow you to untie your code from external resources, static or non-virtual methods, and it is simply impossible to create stubs for which in another way. Here I have shown far from all the functionality of this tool, but this should be enough to understand how it is applicable (or not) for your specific tasks.



via Programming Stuff .

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



All Articles