1

I am trying to generate my baseurl using UriBuilder. I have created a generic "GetRequestUrl" which is in my TestUtil class. How can I get the name of my Test class at run time using this method and append to the string serviceAPI

//Here is the GetRequestUrl method in my TestUtil class

public class TestUtil
{
        public string GetRequestUrl(string serviceName)
        {
            string serviceAPI = this.GetType().BaseType.Name;
            var requestUrl = new UriBuilder();
            requestUrl.Scheme = "http";
            requestUrl.Host = "svc-" + serviceName + "." + 
       ConfigurationManager.AppSettings["TestEnvironment"] + "-example.com/api/";
            requestUrl.Path = serviceAPI;
            Uri uri = requestUrl.Uri;

            return uri.ToString();

        }
}

//Here is my Test class where I want the Class name "TestClass" to append to serviceAPI string at run time, but I am getting TestUtil. I have tried following..

this.GetType().Name;

this.GetType().BaseType.Name;

MethodBase.GetCurrentMethod().DeclaringType.Name;

public class TestClass
{
TestUtil util = new TestUtil();
    [Test]
    public void Method1()
{
     string fullUrl = util.GetRequestUrl("APIServiceName");

}

}
JamesOein
  • 19
  • 4

1 Answers1

0

You need to pass a class in as a parameter to the GetRequestUrl, or the string you want to append. A string is better because it prevents you from needing to change code in the future to adopt to a different practice. To do it the way you seem to want to do is using reflection, which should be avoided if you can do it this way instead:

public class TestUtil
{
    public string GetRequestUrl(string testType, string serviceName)
    {
        string serviceAPI = testType;
        var requestUrl = new UriBuilder();
        requestUrl.Scheme = "http";
        requestUrl.Host = "svc-" + serviceName + "." 
        +     ConfigurationManager.AppSettings["TestEnvironment"] + "-example.com/api/";
        requestUrl.Path = serviceAPI;
        Uri uri = requestUrl.Uri;

        return uri.ToString();
    }
}

public class TestClass
{
    TestUtil util = new TestUtil();
    [Test]
    public void Method1()
    {
        string fullUrl = util.GetRequestUrl(this.GetType().ToString(), "APIServiceName");
    }
}

Another option is to pass it in at the constructor and store it as a private variable, which centralizes the data so that you only pass it in once. Using an interface is preferable to a class:

Using an Interface method:

// An empty interface is fine.
// TestUtil will then require a ServiceAPI for it to be created using it's 
// constructor as a guarantee.
public interface IServiceAPI { }  

using System.Reflection;
public class TestUtil
{
    private _service;
    
    // TestUtil requires a ServiceAPI class.
    public TestUtil (IServiceAPI service) 
    {
        _service = service;
    }
    
    public string GetRequestUrl(string serviceName)
    {
        string serviceAPI = _service.GetType().Name; // Get the class name.
        var requestUrl = new UriBuilder();
        requestUrl.Scheme = "http";
        requestUrl.Host = "svc-" + serviceName + "."
        + ConfigurationManager.AppSettings["TestEnvironment"]
        + "-example.com/api/";
        requestUrl.Path = serviceAPI;
        Uri uri = requestUrl.Uri;

        return uri.ToString();
    }
}
// implement the IServiceAPI interface on TestClass.
public class TestClass : IServiceAPI 
{
    // passing in TestClass here using "this".
    TestUtil util = new TestUtil(this); 
    
    [Test]
    public void Method1()
    {
        string fullUrl = util.GetRequestUrl("APIServiceName");
    }
}
RyanJMcGowan
  • 1,485
  • 1
  • 15
  • 33
  • I'd lean to simply passing `this` and let the `TestUtil` class access the Type. – Charlie Jun 20 '20 at 15:59
  • If you consider that your parameters are a sort of API, passing string allows you flexibility to pass whatever you want in. If you pass this, you'd need a overload you change it. If you did use this, I'd do it through the constructor instead. – RyanJMcGowan Jun 20 '20 at 17:13
  • how to do it in the using in the constructor? should I declared a private variable in my Testutil class like so.. private string GetClassName() { return this.GetType().Name; } – JamesOein Jun 21 '20 at 18:07
  • Not exactly. Create a constructor `TestUtil(TestClass testClass)` that saves it to a private property called `private _testClass`. I like to append an underscore to private properties. Then you can do this `string serviceAPI = _testClass.GetType().ToString();` – RyanJMcGowan Jun 21 '20 at 18:25
  • In that example, it will always return "TestClass" so you should pass in an interface or a base type instead. But I don't know what your base class is or if you're using an in inherited class. Interfaces as a better bet, IMO. – RyanJMcGowan Jun 21 '20 at 18:37
  • my base class consist of all the http methods GET,POST,PUT and Delete generic method. for example when calling the GET method in my TestClass it looks something like this HttpGet(baseUrl, token, client).; – JamesOein Jun 22 '20 at 02:22
  • my base class consist of all the http methods GET,POST,PUT and Delete generic method. for example when calling the GET method in my TestClass it looks something like this HttpGet(baseUrl, token, client); I just name the class TestClass here for simplicity purpose, but my class name is the API I am testing. – JamesOein Jun 22 '20 at 02:28
  • In that case, if TestClass is a subclass of MyBaseClass, you can pass in the base class so it will work with any classthat inherits from MyBaseClass: `TestUtil(MyBaseClass testClass)` This gives you the flexibility. A better method is interfaces, even if it's empty: `interface IServiceAPI {}` and take in an IServiceAPI on your constructor: `TestUtil(IServiceAPI service) {... }` On any class that you want to pass in to TestUtil, implement an IServiceAPI: `class TestClass : IServiceAPI { ... }` Either way, you'll call the constructor the same: `new TestUtil(TestClass testClass);` – RyanJMcGowan Jun 22 '20 at 02:42
  • my tests only inherits the BaseClass – JamesOein Jun 22 '20 at 03:28
  • I revised my answer with an interface implementation. Using an interface is better than a base class anyway. See the revised answer. – RyanJMcGowan Jun 22 '20 at 04:03
  • for some reason I am getting the namespace and then the class name after it. so when I use TestUtil util = new TestUtil(this); it reads as the namespace.classname – JamesOein Jun 22 '20 at 05:03
  • using System.Reflection; – RyanJMcGowan Jun 22 '20 at 05:33
  • .GetType().Name; – RyanJMcGowan Jun 22 '20 at 05:34