.NET Tools: Extract Interface and Implement Wrapper Class
Asked Answered
R

5

8

Is there a tool that can generate extract and generate interfaces for existing classes?

I know Visual Studio will extract an Interface for an existing class. However, I would also like to generate a wrapper class that implements that functionality.

I believe this would help tremendously for unit testing.

Example Existing Class:

public class ThirdPartyClass
{
   public void Method1(){}
   public void Method2(){}
}

This can be generated by Visual Studio (Extract Interface):

public interface IThirdPartyClass
{
   void Method1();
   void Method2();
}

I would like to go one step further:

public class ThirdPartyClassWrapper : IThirdPartyClass
{
   private tpc = new ThirdPartyClass();
   public void Method1()
   {
       tpc.Method1();
   }
   public void Method2()
   {
       tpc.Method2();
   }
}

Update:

This would be especially useful for static classes. As Morten points out I can just use a stub, however, I would like to break up my coupling if possible.

Renaldo answered 17/2, 2011 at 21:57 Comment(3)
any solution about it ??Pepe
Got here in search of the exact same answer. I am voting up the question.Graziano
Upvoting again. EF or VS should have this option.Discreet
G
8

Found a way around it for non-sealed classes.

1 - Inherit from the external class

class MyWrapper : ExternalClass

2 - Extract interface for all public methods

class MyWrapper : ExternalClass, IExternalClass

3 - Remove the inheritance from the external class

class MyWrapper : IExternalClass

4 - You will get a hint on the class name about members from the interface not being implemented. Alt + Enter on it and let Resharper automatically implement them

5 - Use this code template to wrap properties

    get { return $INNERCOMPONENT$.$NAME$; }
    set { $INNERCOMPONENT$.$NAME$ = value; }

6 - Use this code template to wrap methods

return $INNERCOMPONENT$.$NAME$($SIGNATURE$);
Graziano answered 28/11, 2012 at 17:3 Comment(0)
B
3

I don't know a tool that would do that for you.

You probably know, but Visual Studio goes just half step further - it can provide empty implementation of interface. I would stop there if it is one time task.

Depending on actual goal using some other way may work - i.e. for testing you can use mocking frameworks - usually there is a way to wrap existing class and override some methods as needed.

Brigid answered 17/2, 2011 at 22:4 Comment(0)
I
1

Another really slick way of doing this is to use Resharper to generate the "Delegating members" for you as described here: https://mcmap.net/q/624192/-generating-pass-through-code-when-quot-preferring-composition-over-inheritance-quot

Steps:

  1. Create a new class that inherits from the class you want to wrap with a private variable of that class' type:

    public class ThirdPartyClassWrapper : ThirdPartyClass
    {
        private ThirdPartyClass _ThirdPartyClass;
    }
    
  2. Do a Alt-Insert in/on the class to use Resharper to generate "Delegating members". Choose the methods you want to expose and pass through to the private variable.

  3. If you have the free version of the GhostDoc extension installed you can highlight all of the created properties, methods, etc. and do a Ctrl-D to automatically grab all of the documentation from the base class and put it on the new members. (Resharper can do this too but I think you'd have to put "new" on each item which would then allow you to Alt-Enter and choose "Add xml-doc comments" from the Resharper popup menu).

  4. You can then delete the base class and do some additional cleanup in case the method/property signatures expose any other types that you need to wrap.

Iinde answered 6/2, 2015 at 20:46 Comment(0)
T
0

What you are looking for is a stub, this can be done either by making your own stub implementation of the interface, or by using a mocking framework like Rhinomocks. Wrapping a difficult class in another class for testpurposes does nothing good for you.

Regards Morten

Titanothere answered 17/2, 2011 at 23:2 Comment(4)
"Wrapping a difficult class in another class for testpurposes does nothing good for you." I think it would reduce coupling and allow for custom implementation later down the road.Renaldo
Yeah, but why not just stub the interface for now, and let that be the input for your tests? If you are using the implementation, you are also testing that, making your test an integration one.Titanothere
True, I would not test against the ThirdPartyClassWrapper I would stub the interface. However, I am unable to stub a static class. Testing aside, I think it would really benefit later down the road.Renaldo
If the input class is static, you could inject the static functions through delegates. Thus, the use of a method in a static class can be replaced with a non-static/stubbed implementation when testing.Titanothere
F
0

I strongly suggest you look into a mocking framework like Fakeiteasy.

But to give you exactly what you asked for see below. I suspect ReSharper didn't have this operation when others answered.

  1. add the interface to the class you wish to be the wrapping class

    class MyWebElement : IWebElement { }
    

  1. Find/Click "Delegate implementation of "YourInterfaceHere" to a new field Delegate Implementation

  1. Select your options Delegate options

  1. Click finish and enjoy your new class

    class MyWebElement : IWebElement
    {
        private IWebElement _webElementImplementation;
        public IWebElement FindElement(By @by)
        {
            return _webElementImplementation.FindElement(@by);
        }
    
        public ReadOnlyCollection<IWebElement> FindElements(By @by)
        {
            return _webElementImplementation.FindElements(@by);
        }
    
        public void Clear()
        {
            _webElementImplementation.Clear();
        }
    
        public void SendKeys(string text)
        {
            _webElementImplementation.SendKeys(text);
        }
    
        public void Submit()
        {
            _webElementImplementation.Submit();
        }
    
        public void Click()
        {
            _webElementImplementation.Click();
        }
    
        public string GetAttribute(string attributeName)
        {
            return _webElementImplementation.GetAttribute(attributeName);
        }
    
        public string GetCssValue(string propertyName)
        {
            return _webElementImplementation.GetCssValue(propertyName);
        }
    
        public string TagName
        {
            get { return _webElementImplementation.TagName; }
        }
    
        public string Text
        {
            get { return _webElementImplementation.Text; }
        }
    
        public bool Enabled
        {
            get { return _webElementImplementation.Enabled; }
        }
    
        public bool Selected
        {
            get { return _webElementImplementation.Selected; }
        }
    
        public Point Location
        {
            get { return _webElementImplementation.Location; }
        }
    
        public Size Size
        {
            get { return _webElementImplementation.Size; }
        }
    
        public bool Displayed
        {
            get { return _webElementImplementation.Displayed; }
        }
    }
    
Fimble answered 11/1, 2017 at 15:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.