0

I am trying to get the stored String Object in ThreadLocal in my BaseClass to the TestClass. In the following code I have defined the ThreadLocal and stored a String by set() method. But when I try to get that stored string in my TestClass that extends BaseClass it becomes null. What am I missing here?

My BaseClass code is as follows:

package base;

import org.testng.annotations.BeforeSuite;

public class BaseClass {

    private static final ThreadLocal<String> str = new ThreadLocal<>();

    public void setString(String string){
        str.set(string);
    }

    public static String getString(){
        return str.get();
    }

    @BeforeSuite
    public void setDesiredString(){
        String desiredString = "I am a String.";
        setString(desiredString);
    }

}

And my TestClass code is as follows:

package tests;

import base.BaseClass;
import org.testng.Assert;
import org.testng.annotations.Test;

public class TestClass extends BaseClass {

    String str = getString();

    @Test
    public void TestString() {

        Assert.assertEquals(str,"I am a String." );
    }

}

When I run the TestClass, I get the following output:

java.lang.AssertionError:
Expected :I am a String.
Actual   :null

I am expecting to have a passed test having same Expected & Actual string that was stored in the ThreadLocal in BaseClass via setDesiredString() which is "I am a String."

  • 1
    in the code you provided , you are not calling setDesiredString() method anywhere, it will be null only – Abhay Chaudhary May 08 '23 at 13:07
  • Oops, my bad. I was reproducing the problem and messed up. However, I have updated the code. Please take a look again. Thanks. – Aliul Islam Abir May 08 '23 at 13:32
  • You seem to assume that the `@BeforeSuite` method is called on the same thread as the `@Test`, and I'm not sure that assumption holds. – Joachim Sauer May 08 '23 at 13:34
  • You maybe right. I do have a suspicion about that but I don't have a clear understanding of this matter. If, that's true I'm really hoping to have a good explanation about why and how this is not working. Can you help? – Aliul Islam Abir May 08 '23 at 13:39
  • 2
    The initializer of `String str = getString();` is executed when the object is constructed. Since it is impossible to invoke the instance method `setDesiredString()` before the object has been constructed, it’s clear that it must happen after the `str` variable has been initialized; you don’t need to know anything about TestNG for this conclusion. – Holger May 08 '23 at 15:10
  • 2
    @JoachimSauer it doesn’t matter in which thread the `@Test` method is executed, as in this code, the test method doesn’t access the thread local variable. – Holger May 08 '23 at 15:12
  • So, what is the solution? – Aliul Islam Abir May 09 '23 at 01:29

1 Answers1

0

you can Base class like below to make it work

import org.testng.annotations.BeforeSuite;


public class BaseClass {

    private static final ThreadLocal<String> str = new ThreadLocal<>();

    public void setString(String string) {
        str.set(string);
    }

    public String getString() {
        return str.get();
    }

    @BeforeSuite
    public void setDesiredString() {
        String desiredString = "I am a String.";
        setString(desiredString);
    }


}

And in Test class just call the Threadlocal getter method

import org.testng.Assert;
import org.testng.annotations.Test;

public class TestClass extends BaseClass {

    @Test
    public void TestString() {

        Assert.assertEquals(getString(), "I am a String.");
    }

}
Abhay Chaudhary
  • 1,763
  • 1
  • 8
  • 13