Share data between specflow scenarios

1.3k views Asked by At

In our application i need to open 3 absolutely same documents, for each document i have a button with unique locator, as we are executing tests in parallel i need to know which document already opened and open another one which is not used, i'm not able to open one documents in parallel. My scenarios should share the status of which document has been opened and which is available for editing. Is it possible to share such data between scenarios?

I have checked everything what has been possible IObjectContainer and was created GlobalContainer using var Container = new ContainerBuilder().CreateGlobalContainer();, but nothing works.

UPDATE:

Solution has been found, we should pass TestThreadContext to hooks constructor, but this will work only if we will use one thread:

private readonly TestThreadContext _context;

private Hooks(ScenarioContext scenarioContext, TestThreadContext context)
    {
        ScenarioContext = scenarioContext;
        _context = context;
        if (!_context.TestThreadContainer.IsRegistered<Dictionary<int, bool>>("myObject"))
            _context.TestThreadContainer.RegisterInstanceAs(MyDictionary, "myObject"); // you can register any object not only dictionary.
    }

    [BeforeScenario]
    private void BeforeScenario()
    {
        var myDictionary = _context.TestThreadContainer.Resolve<Dictionary<int, bool>>("myObject"); // to get your dictionary back from container
    }

If you would like to share data between parallel test scenarios, you should create new AppDomain in GlobalStep(SpecRun) and pass to this app domain your class with data and methods which can return data and update data, this can be done using yourDomain.SetData("youKey", new yourClass), then in Hooks you should get your domain (how to get required app domain) and from domain get your added class var data = domain.GetData("yourKey") and then you can call your methods data.YourMethod(); also you should lock lines inside your methods to be thread safe using lock(object) {your code}.

2

There are 2 answers

1
Koncervator On

Why don't create a generic step for opening a doc with specified ID like this:

[Then(@"User opens document with ID ""(.*)""")]
public void ThenUserOpensTheDocument(string docId)
{
}

and then call it from the Specflow scenarious like this:

User opens document with ID "1234567"

So you will call this step 3 times from different test scenarios, each call with own document ID.

1
Gaspar Nagy On

I am not sure I fully understand the situation. Generally you can run tests parallel (with SpecRun alias SpecFlow+ Runner) in two different ways, and the solution also depends on which one you use.

  1. You can run the test threads in appdomain isolation. In this case, there is a new AppDomain created for each thread. AppDomains have isolated memory, so you cannot create a "global" dictionary that is accessible from all threads. In this case, you have to share state somehow else, like creating empty files in the temp folder. (You can name your files based on your document, like mydoc1.lock, and check for the existence of the file, create/delete the file accordingly.)

  2. You can run the tests in the same appdomain. (This is what you can also do with xunit/nunit.) In this case, you can simply declare a static field for the dictionary, and it will be shared across all threads. (You have to protect your reads/writes of course, because the Dictionary is not thread safe by default.)