0

I am using C# and NUnit framework for executing multiple test in separate threads simultaneously. I want to record the time between certain actions and have created an ActionTimeHelper class for the same.

Below is the code for the class and the context in which methods in the class are used

When I run two test in parallel bot of which call the Login method then only one test completes and the other one throws an error

(Message: System.NullReferenceException : Object reference not set to an instance of an object.
) at actionList.Add(new ActionTimeInfo()

I have made the actionList as ThreadStatic so that every test which runs on its own thread has its own copy, so I am not able to figure out why am getting the error.

Note: If I run one test at a time everything works fine

Can someone please guide me on this. Thanks for the help.

Have read some articles Referencing a non static member with an instantiated object, Referencing an instantiated object in a static class (c#) but not able to relate ti my specific problem

public static class ActionTimeHelper
{
private static readonly string _actionTimeLogFileName = "ActionTimeLog_" + string.Format("{0:yyyy_MM_dd_hhmmss}", DateTime.Now);
[ThreadStatic] private static FileStream _fileStream = null;
[ThreadStatic] private static StreamWriter _actionStreamWriter = null;
[ThreadStatic] private static JsonWriter _jsonWriter = null;
[ThreadStatic] private static List<ActionTimeInfo> actionList = new List<ActionTimeInfo>();

public static void CreateActionTimeLogFile(string logPath, string testName)
{
    string dir = logPath + testName + @"\";
    if (!Directory.Exists(dir))
    {
        Directory.CreateDirectory(dir);
    }
    _fileStream = File.Open(dir + _actionTimeLogFileName + ".json", FileMode.CreateNew);
    _actionStreamWriter = new StreamWriter(_fileStream);
    _jsonWriter = new JsonTextWriter(_actionStreamWriter);
    _jsonWriter.Formatting = Formatting.Indented;
    JsonSerializer serializer = new JsonSerializer();
    serializer.Serialize(_jsonWriter, actionList);
    _fileStream.Flush();
    _actionStreamWriter.Flush();
    _jsonWriter.Flush();

}

public static void StartActionTime(string actionName)
{

    actionList.Add(new ActionTimeInfo()
    {
        TestName = TestContext.CurrentContext.Test.Name,
        ActionName = actionName,
        StartTime = DateTime.Now
    });
}

public static void EndActionTime(string actionName)
{
    ActionTimeInfo endAction = actionList.Find(actionInfo => actionInfo.ActionName.Equals(actionName));
    endAction.EndTime = DateTime.Now;
    endAction.ExecutionTime = endAction.EndTime.Subtract(endAction.StartTime);
}

}

public class ActionTimeInfo
{
public string TestName { get; set; }

public string ActionName { get; set; }

public DateTime StartTime { get; set; }

public DateTime EndTime { get; set; }

public TimeSpan ExecutionTime { get; set; }
}


public void Login(string username, string password)
{
    ActionTimeHelper.StartActionTime("Navigating to URL");
    ActionTimeHelper.EndActionTime("Navigating to URL");
    ActionTimeHelper.StartActionTime("Login Action");
    ActionTimeHelper.EndActionTime("Login Action");
    Thread.Sleep(30000);
}

[TearDown]
public void TestTearDown()
{
    ActionTimeHelper.CreateActionTimeLogFile(LogPath, TestContext.CurrentContext.Test.Name);
}

Actual result: Null reference error Expected result: No null reference error

test_user
  • 49
  • 7
  • Possible duplicate of [What is a NullReferenceException, and how do I fix it?](https://stackoverflow.com/questions/4660142/what-is-a-nullreferenceexception-and-how-do-i-fix-it) – Ňɏssa Pøngjǣrdenlarp Apr 27 '19 at 02:15
  • I understand the NullReferenceException but when every test is running in its own thread and every thread is having its own actionList then why the NullReferenceException ? Shouldn't the other test running in parallel have instantiated its own List of ActionTimeInfo class ? Also when I run one test at a time no exception is received – test_user Apr 27 '19 at 02:52

1 Answers1

1

“Do not specify initial values for fields marked with ThreadStaticAttribute, because such initialization occurs only once, when the class constructor executes, and therefore affects only one thread. If you do not specify an initial value, you can rely on the field being initialized to its default value if it is a value type, or to null if it is a reference type.“

From

https://docs.microsoft.com/en-us/dotnet/api/system.threadstaticattribute?view=netframework-4.8

Neil.Work
  • 885
  • 6
  • 9