Is RawVsServiceProvider not Available in Tests?

I set up a test project for my R# plugin. In this plugin there's a ShellComponent that's expecting RawVsServiceProvider as a constructor parameter. When I start the plugin, everything works just fine. The ShellComponent gets instatiated and is provided with the requested provider. When I run the tests, however, they fail with an exception, saying that "The component ActionEventInstrumentationComponent constructor requires JetBrains.VsIntegration.Application.RawVsServiceProvider, which we do not have." I made sure that the assembly JetBrains.Platform.ReSharper.VisualStudio.Code, which contains the respective class, is actually referenced by both the plugin and the test assembly. Is the RawVsServiceProvider not available in tests or am I doing something else wrong?

Thanks!
Best,
Sven

13 comments

RawVsServiceProvider wraps a Visual Studio interface, and is used to get Visual Studio services. Since the tests don't run inside Visual Studio, this class can't do anything and doesn't get registered - in fact, it's the Visual Studio integration code that creates it. If your ShellComponent requires VS support, it is best to use

[SolutionComponent(ProgramConfiurations.VS_ADDIN)]
on the component. This tells the component model not to try and instantiate this component if it's not running in Visual Studio.

While it doesn't help with tests, you might find that the service you're trying to get via RawVsServiceProvider is already exposed - take a look at VsServiceResolver in dotPeek to see what VS services and interfaces are exposed. It's also worth looking at various implementations of IExposeVsServices to see what else is exposed and to see how you can also expose VS services to the container, ready to be injected into your constructor parameters. You can see more here: http://confluence.jetbrains.com/display/NETCOM/2.02+Component+Model+%28R8%29
0

Thanks for the answer, Matt. This is what I feared... the service I'm looking for is one registered by one of our projects, so it's not exposed. Do you know if there is a way to register a mock of that service to R#? That would provide even better test isolation than accessing the actual service...

Best,
Sven

0

I haven't tried adding a component in tests. Generally, the container is created based on a manifest that's compiled into the SDK assemblies. It might be possible to just have a class in your test assembly decorated with [ShellComponent] and have it work.

0

Unfortunately, that doesn't seem to work. And in fact, it makes sense that it doesn't. Because the tested assembly has no reference to the test assembly, it cannot get an instance from a class defined there. Even if the class has the correct Namespace and Name. I guess I have to think of something else... like not using VSServices to provide our MessageBus...

0

Ah, sorry, I was thinking in terms of interfaces. You can declare an interface in the production assembly and implement it in both the production code and the test code. As long as the production code has the VS_ADDIN parameter, only one will be loaded into the test container.

A good rule of thumb with ReSharper plugins is to try to avoid Visual Studio interfaces and objects - since ReSharper needs to run on as many versions of VS as possible, it's pretty good at abstracting VS or providing alternatives to what's already there. There's a "DataFlow" namespace that provides interesting objects that might help - IProperty, ISignal and IViewable especially, although they may be more focussed on events than a message bus. So you could also take a look at the EventBus namespace, which appears to offer a full event bus with subscriptions and lifetimes and so on, but I must admit I've never looked at how it works, or really what it does :) Alternatively, if you're just using VS services to wire things up for you, then lean on the component model - create your own ShellComponent and SolutionComponent attributed classes and inject them into constructors.

0

I've seen the R# EventBus, but my bus is currently used by both R# plugins and VSPackages. Thus, it seemed easier to make a VSService available in R# plugins than the other way round...

In fact, your last comment helped me to move on step farther: Instead of using the RawVsServiceInterface directly in my components, I added a ShellComponent(VS_ADDIN) that implements my MessageBus interface. This component expects the RawVsServiceProvider as constructor parameter and internally delegates to the read message bus. In the test project I added a ShellComponent-implementation of the MessageBus interface that appends the messages to a list for later validation. mY actual components now only depend on the MessageBusInterface and get the respective Component injected. This gives me usage of the VsService in production and a mock in the testing environment. I find this a nice solution, actually.

Unfortunately, now I'm facing a similar problem with the DTE interface. In production mode I get DTE injected. In test execution injection fails. But DTE is actually part of the interfaces exposed by R# [1]. While I could apply the same trick here, I'm not really sure why DTE is not available in the testing environment, since according to what you wrote earlier it should be... Is there a special DTE interface, declared in some R# assembly? I'm currently using EnvDTE.DTE from the envdte assembly. This works for production and I cannot find another DTE interface. Can you explain that phenomenon?

Best,
Sven

[1] http://confluence.jetbrains.com/display/NETCOM/2.02+Component+Model+%28R8%29

0

That list is the list of interfaces implemented by Visual Studio that are exposed by ReSharper's component model, but they can only be exposed when your plugin is run inside Visual Studio - ReSharper doesn't provide a mock implementation for them when running in the standalone test (i.e. non-VS) environment. I'd do the same trick with DTE - expose an interface that describes your requirements and implement it via DTE in the production code, and with a stub implementation in the test code.

Out of interest, how are you registering the message bus with Visual Studio from the ReSharper plugin?

0

Ah ok, I see. Thanks. Another thing that should really be stated in the docs...

I don't register the bus from a R# plugin. I do it from a VsPackage and only access in the the R# plugin. This is because I currently want to use the same bus in a VsPackage and in a R# plugin.

Best,
Sven

0

I blogged about what I've drawn from this discussion at http://sven-amann.de/blog/2013/11/how-to-use-visualstudio-dependencies-in-r-plugins/. Hopefully it helps someone experiencing similar problems in the future ;)

0

I'm interested in the integration between the R# plugin and the VSPackage. I've got a project which is intended to make it a bit easier to handle extensions that are both R# plugins and VSPackages - https://github.com/JetBrains/resharper-vsix. There are actually two projects, and they do similar things, but from different directions. One is an extension to Visual Studio that allows loading a ReSharper extension that's bundled inside another VSIX - so if you have a VSIX that could provide added value to ReSharper users, you can optionally have it load a resharper extension. The other project is a ReSharper extension that enables installing VSIX files, allowing deeper VS integration than ReSharper allows, such as registering and exporting your message bus. And since both VSIX and ReSharper extensions allow specifying dependencies that must be installed before use, getting these extensions installed is pretty easy.

The project is still a little rough - I haven't had chance to provide samples yet, and the API is most likely going to change, but I'd be interested in your opinion. Is this something that could be useful?

0

From a quick read I take that your project(s) are primarily concerned with packaging. I must admit that my current status is not that advanced that I spend too much thought on packaging. Anyways, the general idea sounds really good to me. I think the way  for me to go would be to extend my R# plugin by some low-level vsix stuff to get it all working. It would be really great to have some tools at hand that manage the integration for me. I'm realatively new to the world of C#, VisualStudio, and R# and welcome anything that takes some low-level integration work of my shoulders, as I currently feel like drowning in it ;\

0

If you're starting C# by looking into VS and ReSharper extensions, you've really dived into the deep end :)

The big problem with ReSharper extensions using anything VSIX related is that Visual Studio requires all extensions to be statically registered, and ReSharper plugins are dynamically loaded each time VS/R# restarts (VS caches the MEF registration information when an extension is installed. ReSharper also caches its component model registrations at startup, but can handle dynamically added assemblies). This means your ReSharper extension can't import or export MEF objects - Visual Studio doesn't know they exist! That's why I started with these projects, and yes, they're all about deployment. I've started work on samples to show how to talk between VS extensions and R# extensions, and I'm looking at how I can make it easy to integrate the two. Will hopefully get time to get back to it soon.

0

I'm working in a research project with the goal to bring intelligent code completion, such as provided by Eclipse Code Recommenders, to VS. Switching the target plattform of our recommendations brings both, the new language and the need to lurk around in the depths of an unknown IDE. After all, slowly letting yourself down into a freezing lake wouldn't be half as fun as jumping right into it, would it? ]:)

As I said before, I think the goal of your project is really good. The sad thing is that such things need to be hacked, instead of beeing provided natively by the IDE... but maybe that's just the Eclipse user in me and I shouldn't expect easy extendability in a monolith such as VS. ;)

0

Please sign in to leave a comment.