The Problem:
I have two features (I'm just getting started with SpecFlow)
In each of the feature steps, I create a global WebDriver so that I can use it for all of the steps. If I run just the steps, everything runs correctly in both features. They do, however, leave the browser window open because I never close the WebDriver. So my thought was to put an AfterFeature fixture in each of the Step files do close the driver.
[AfterFeature]
public static void ShutDown()
{
Driver.Close();
}
When I run each feature, everything is fine and the driver closes at the end of the run. However, if I run more than one feature like this, the driver will close after the first feature and a new one will not open when the next feature starts. I find this odd since each feature steps file has it's own instantiated driver.
I have learned that if I use [AfterTestRun], the tests will run correctly and both browsers will remain open until all features are complete. At which point they will both close. This is ok for now when I only have two features, but when I get a bunch, I would rather not have a bunch of random browser windows sticking around until all the tests are completed.
I think this might be somehow related to my inability to use [AfterScenario] without breaking my tests. I was trying to use [AfterScenario] to logout after each scenario/test, but when I do I see a random blank driver/browser window pop up at the end of my first test (regardless of which test I run first).
I have this feeling that I'm just missing some sort of paradigm with this whole BDD methodology here, and that things are actually working as designed. But I am at a loss as to what changes I should make. Here is an example of my login tests.. Is there something fundamental that I'm missing here?
The Code:
Login.feature
Feature: Login
In order to be able to use Laserfiche
As a legitimate user
I want to be able to log into the repository
#SmokeTest
Scenario: Login with correct credentials
Given I am on the Login page
And I have a good username/password combination
And I select a repository
When I fill out the form and submit
Then I am taken to the repo page
---------------
LoginSteps.cs
using NUnit.Framework;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using Selenium_C_Sharp_POC.Page_Object_Files.Pages;
using Selenium_C_Sharp_POC.Page_Object_Files.Test_Tools;
using TechTalk.SpecFlow;
namespace Selenium_C_Sharp_POC.StepDefinitions
{
[Binding]
public class LoginSteps
{
private static readonly IWebDriver Driver = new ChromeDriver();
private static LoginPage _loginPage;
private static string _username;
private static string _password;
private static string _repo;
[AfterTestRun]
public static void ShutDown()
{
Driver?.Close();
}
[Given(#"I am on the Login page")]
public void GivenIAmOnTheLoginPage()
{
_loginPage = new LoginPage(Driver);
}
[Given(#"I have a good username/password combination")]
public void GivenIHaveAGoodUsernamePasswordCombination()
{
_username = Nomenclature.WebClientPersonalUsername;
_password = Nomenclature.WebClientPersonalPassword;
}
[Given(#"I select a repository")]
public void GivenISelectARepository()
{
_repo = Nomenclature.RepoUnderTest;
}
[When(#"I fill out the form and submit")]
public void WhenIFillOutTheFormAndSubmit()
{
_loginPage.Login(
username: _username,
password: _password,
repo: _repo);
}
[Then(#"I am taken to the repo page")]
public void ThenIAmTakenToTheRepoPage()
{
Assert.AreEqual(
expected: _repo,
actual: Driver.Title);
HelperMethods.Logout(Driver);
}
}
}
Edit: Added Login Page Class code
using System;
using OpenQA.Selenium;
using System.Threading;
using OpenQA.Selenium.Support.UI;
using SeleniumExtras.WaitHelpers;
using Selenium_C_Sharp_POC.Page_Object_Files.Test_Tools;
namespace Selenium_C_Sharp_POC.Page_Object_Files.Pages
{
class LoginPage
{
private readonly IWebElement _repoDropDown;
private readonly IWebElement _usernameTextBox;
private readonly IWebElement _passwordTextBox;
private readonly IWebElement _submitButton;
private readonly IWebDriver _driver;
private readonly IWebElement _warningBox;
public LoginPage(IWebDriver driver)
{
_driver = driver;
HelperMethods.OpenWebPage(
domain: Nomenclature.Domain,
driver: _driver,
subPage: Nomenclature.LoginPageFilename
);
_repoDropDown = _driver.FindElement(By.Id("SelectedRepo"));
_passwordTextBox = _driver.FindElement(By.Name("password"));
_usernameTextBox = _driver.FindElement(By.Name("username"));
_submitButton = _driver.FindElement(By.Id("LoginButton"));
_warningBox = _driver.FindElement(By.ClassName("alert-danger"));
}
public void Login(string username, string password, string repo)
{
SelectRepo(repo);
_usernameTextBox.SendKeys(username);
_passwordTextBox.SendKeys(password);
_submitButton.Click();
WaitForLoginToComplete();
}
public void SelectRepo(string repo)
{
_repoDropDown.Click();
var options = _repoDropDown.FindElements(By.XPath(".//option"));
foreach (var option in options)
{
if(option.Text.Equals(repo))
option.Click();
}
}
public bool WarningDisplayed_UsernamePassword()
{
Thread.Sleep(500);
return _warningBox.Displayed &&
_warningBox.Text.Equals(Nomenclature.BadUsernameOrPasswordText, StringComparison.OrdinalIgnoreCase);
}
internal bool OpenedRepoPage(string expectedRepo)
{
return _driver.Title.Equals(expectedRepo);
}
internal void WaitForLoginToComplete()
{
try
{
var wait = new WebDriverWait(_driver, TimeSpan.FromSeconds(5));
wait.Until(ExpectedConditions.ElementIsVisible(By.ClassName("alert-danger")));
}
catch (Exception)
{
var wait = new WebDriverWait(_driver, TimeSpan.FromSeconds(45));
wait.Until(ExpectedConditions.ElementExists(By.XPath("//*[#ng-model='searchQuery']")));
wait.Until(ExpectedConditions.InvisibilityOfElementLocated(By.ClassName("entryListLoadingSpinner")));
}
}
}
}
LatestInfo:
I believe I know why this is happening. I just don't know the proper way to fix it. As an experiment, I changed the WebDriver for my search tests to Firefox and left the WebDriver for my login tests as Chrome. No matter what test(s) I ran, I always saw 2 browsers open; one Chrome and one Firefox.
When I moved all of the steps from my SearchTestSteps.cs file into the LoginTestSteps.cs file, the problem disappeared.
So, yeah, this solves the immediate issue, but it is sub-optimal to have all of my steps in a single file. That can quickly become unwieldy.
Since each set of steps needs to have its own WebDriver, I'm at a loss.
Might this have something to do with folder structure and where things are stored? Here is what mine looks like.
Root
|-Page Object Files
|- Page Components
|- Pages
|- Test Tools
|- Step Definitions
|- <*Steps.cs>
|- TESTS
|- BDD Tests
|-<*.feature>
|- *standard selenium test files*
After investigating some more, I realized that the problem is NOT what I thought it was, and therefore the title and contents were inaccurate. I am closing this question and creating a new question with more accurate Title and information.
Having Multiple Step Files Opens Multiple Browsers
Related
I created a xunit project and added specflow with Gherkin and selenium web drivers to the project. I've following StepDefinition file,
[Binding]
public class MyPageStepDefinition
{
private readonly UserContext _userContext;
private readonly ConfigurationDriver cd;
public MyPageStepDefinition(UserContext userContext)
{
_userContext = userContext;
cd = new ConfigurationDriver();
}
// Many Given, when and Then
}
I've UserContext file as follows,
public class UserContext
{
public string email { get; set; }
}
I'm using IObjectContainer to get help with ContextInjection in specflow as follows,
[Binding]
public class BrowserDriver
{
private readonly IObjectContainer _objectContainer;
// BrowserType is enum
public Dictionary<BrowserType, IWebDriver> _drivers;
public BrowserDriver(IObjectContainer objectContainer) {
_objectContainer = objectContainer;
_drivers = new Dictionary<BrowserType, IWebDriver>();
}
[BeforeScenario]
public void BeforeScenario()
{
_objectContainer.RegisterInstanceAs(_drivers);
}
}
My browser initialization code,
public IWebDriver InitBrowser(BrowserType browser)
{
IWebDriver driver = null;
switch (browser)
{
case BrowserType.Chrome:
ChromeOptions chromeOptions = new ChromeOptions();
if (!Debugger.IsAttached)
{
chromeOptions.AddArgument("headless");
chromeOptions.AddArguments("disable-gpu");
chromeOptions.AddArguments("window-size=1900,1280");
chromeOptions.AddArguments("--no-sandbox");
chromeOptions.AddArguments("--ignore-certificate-errors");
chromeOptions.AddArguments("--disable-dev-shm-usage");
}
driver = new ChromeDriver(chromeOptions);
break;
}
driver.Manage().Window.Maximize();
//driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(10);
return driver;
}
I call above method as follows,
SupportedBrowserList().ForEach(b => _drivers.Add(b, _testContext.InitBrowser(b)));
public List<BrowserType> SupportedBrowserList()
{
return new List<BrowserType>
{
BrowserType.Chrome,
};
}
and I use _drivers as follows,
GetCurrentDriverList(_drivers).ForEach(d =>
{
// Do something on webpage, like d.FindElement(..);
});
public List<IWebDriver> GetCurrentDriverList(Dictionary<BrowserType, IWebDriver> drivers)
{
return new List<IWebDriver>(drivers.Values);
}
I've 2 features files to handle 2 flows. Most of the steps are common so they both call MyPageStepDefinition constructor. When I run the feature files parallelly (default behavior of xunit) then one or the other test case fail, saying the email is not matching. I was able to debug and understand, that the email of one test is going in another. Looks like there is some race condition in Context Injection in specflow in parallel execution.
To validate my hypothesis, I made the test run sequentially using xunit.runner.json file with following configuration,
{
"parallelizeTestCollections": false
}
and the code worked flawlessly. Now, if I run again in parallel it fails. It confirmed my hypothesis that specflow+xunit in parallel run is causing some issues. I'm pretty sure someone must have faced similar issue and fixed it, but I can't seem to figure it out. Can someone please help me in this? And How can I fix this?
Note: I've made the file simple, the UserContext has more data fields. None of the fields are static in UserContext.
So as we know when you use SpecFlow if you reuse a step from another test it automatically pulls it in and reuses it... however, I have the issue whereby Test A logs me in and test B logs in and confirms the home page is correct but as test A is initialising ChromeDriver when I come to use Test B my Driver wants to open another webpage causing the test to fail as its open an empty webpage.
My question is - How do I use the driver without it opening another instance of Chrome. Here is what I have code wise for my 'generic login:'
private LandingPageCode landingPage;
private HomePageCode HomePage;
[Given(#"I have entered my username, password selected login")]
public void GivenIHaveEnteredMyUsernamePasswordSelectedLogin()
{
driver = new ChromeDriver();
driver.Url = ("my URL");
landingPage = new LandingPageCode(driver);
HomePage = new HomePageCode(driver);
The code I have on test B which validates the homepage once logged in:
{
private ChromeDriver driver;
private HomePageCode HomePage;
private LandingPageCode landingPage;
[Given(#"Successfully log into Cal's website (.*)")]
public void GivenSuccessfullyLogIntoOptix(Decimal p0)
{
driver = new ChromeDriver();
HomePage = new HomePageCode(driver);
landingPage = new LandingPageCode(driver);
driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(5);
Assert.AreEqual("HomePage", driver.Title);
I see this question or related ones very frequently (How to properly manage and access webdriver instances to avoid problems with parallel execution of tests?). Integrating Selenium and SpecFlow can be tricky. You need to leverage the dependency injection framework that comes with SpecFlow, and use before and after scenario hooks to initialize the web driver, then register it with the dependency injection container. Later on in your step definition classes, you need to specify a constructor for those classes that accepts an IWebDriver object as a constructor parameter, and assign it to a field on each step definition class.
[Binding]
public class WebDriverHooks
{
private readonly IObjectContainer container;
public WebDriverHooks(IObjectContainer container)
{
this.container = container;
}
[BeforeScenario]
public void CreateWebDriver()
{
// or new FirefoxDriver or new WhateverDriver as long as it implements
// the IWebDriver interface
ChromeDriver driver = new ChromeDriver();
// Make 'driver' available for DI
container.RegisterInstanceAs<IWebDriver>(driver);
}
[AfterScenario]
public void DestroyWebDriver()
{
var driver = container.Resolve<IWebDriver>();
if (driver != null)
{
driver.Quit();
driver.Dispose();
}
}
}
And a sample step definition file:
[Binding]
public class LoginSteps
{
private readonly IWebDriver driver;
private readonly LoginPage loginPage;
public LoginSteps(IWebDriver driver)
{
// Assign 'driver' to private field or use it to initialize a page object
this.driver = driver;
// Initialize Selenium page object
this.loginPage = new LoginPage(driver);
}
[When(#"I go to the login page")]
public void WhenIGoToTheLoginPage()
{
// Use 'driver' in step definition
driver.FindElement(By.LinkText("Sign In")).Click();
}
[When(#"I log in")]
public void WhenILogIn()
{
// Use Selenium page object in step definition
loginPage.LogIn("testUser", "testPassword");
}
}
This not only allows you to share web driver instances across step definition files, but it centralizes the logic of creating and disposing of these objects, and brings you one step closer allowing parallel tests execution.
See also: Context Injection on SpecFlow.org.
You could remove your driver code from your tests and set up a framework for your code to run on. Using NUnit, you could develop a framework for yourself to run the tests in parallel. There are tones of online tutorials for this. [https://nunit.org/][1]
You could create a driver.cs class that looks like this which pulls the base URL from a config class.:
public static class Driver
{
public static IWebDriver driver = new ChromeDriver();
public static void InitializedDriver()
{
Driver.driver.Navigate().GoToUrl(Config.BaseURL);
Driver.driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(5);
}
}
Then in your test class, you can use OneTimeSetUp to initialise your web driver:
[OneTimeSetUp]
public void Initialize()
{
Driver.InitializedDriver();
}
After your test codes, you can then tear down using:
[OneTimeTearDown]
public void CleanUp()
{
Driver.driver.Quit();
}
This would allow your tests to run on the same Chrome instance.
I'm currently mantaining a solution of tests using selenium and specflow, and I was running everything in parallel smoothly, sharing a sigle webdriver between browser(chrome) windows.
But now i had to add a couple of scenarios that involve switching between frames, and the tests started to break randomly when run in parallel due to elements or iframes not being found.
Anyone has had this problem and knows a good way to solve this?
Edit: Some code
This is in the class I use to set up my test run
private readonly IObjectContainer objectContainer;
private ChromeWebDriver chromeWebDriver;
public TestSetup(IObjectContainer container)
{
this.objectContainer = container;
}
[BeforeScenario]
public void SetUp()
{
chromeWebDriver = new ChromeWebDriver();
objectContainer.RegisterInstanceAs<ChromeWebDriver>(chromeWebDriver);
}
Then in the step file I'll initialize the webdriver in the constructor
private readonly IWebDriver driver;
public LoginSteps(ChromeWebDriver chromeWebDriver)
{
this.driver = chromeWebDriver.WebDriver;
}
#Dayan54 - Please take a look at the below. I run 4-6 threads in SpecFlow and I have iFrames with no issues. Maybe this will help.
Also I have seen this so I have to ask. in some iFrames, like say social media login for FaceBook or InstaGram, when you login, it closes the iFrame automatically. This will then throw an error on anything else you do because if you try and close it, you get an error since it is already closed. Switch to main content will fail because you are already there. For that I wrote the "GoToMainHandle" method.
//switch to the iframe name -
public static void SwitchToIframe(string frameName)
{
try
{
Driver.SwitchTo().Frame(frameName);
}
catch (NoSuchFrameException)
{
try
{
Driver.SwitchTo().Frame(frameName);
}
catch (NoSuchFrameException)
{
Console.WriteLine("Could not switch to IFrame");
throw;
}
}
}
//going back to main content when completed with iframe
public static void SwitchToMainContent()
{
Driver.SwitchTo().DefaultContent();
}
//If the iframe closes automatically, you still need to get back to the main window
public static void GoToMainHandle()
{
var handles = Driver.WindowHandles;
foreach (var handle in handles)
{
Driver.SwitchTo().Window(handle);
break;
}
}
I have been spending the last 3 Months teaching myself Automated Testing. Having had no previous experience (manual tester who had never coded in my life) I have (with the help of this Board) managed to create a selenium Object Based Framework, written tests that link to this framework and got all my tests to run.
However I now need to take my test suite and pass it through multiple environments on a cloud based service. The problem I have is that I have to define the environment each time I run the test set. Ideally I want to be able to define the environments I run my tests on (Firefox, Chrome, IE etc), and then set the test suite off to run my set of 17 tests 3 times across each browser.
I Don't want to set up a system to run this locally but instead have a method that calls my different methods for my Cloud Service (currently trialling a couple)
a Sample of my code is as follows
Test Code - Login
namespace Kukd_Consumer_Test
{
[TestFixture]
public class Login : Consumer_Standard_Functionality
{
[Test]
public void User_Can_Login()
{
LoginPage.LoginAs("xxxxxxxxxx").WithPassword("xxxxxxx").Login();
Assert.IsTrue(AccountPageBtns.IsAtAccountPage("Hi Richard"), "Failed to login");
AccountPageBtns.Logout();
}
}
}
My standard Functionality (call driver go to homepage, quit etc) Currently I have to comment all but one of my Driver Methods. I want to be able to define multiples here Ideally so I can define which environments I run my tests on (locally or cloud based)
public class Consumer_Standard_Functionality
{
[SetUp]
public void Init()
{
// currently have to comment out all but the one I want to run.
driver.InitializeChrome();
//driver.InitializeFireFox();
//CBT_Driver.InitialiseChromeCBT(testName);
//CBT_Driver.InitialiseFFCBT(testName);
//CBT_Driver.InitialiseIECBT(testName);
//driver.InitialiseBrowserStack();
Homepage.GoTo_HomePage();
}
[TearDown]
public void Cleanup()
{
driver.Quit();
}
My local Driver Class (plus browserstack)
using NUnit.Framework;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Firefox;
using OpenQA.Selenium.Remote;
using System;
namespace Kukd_Consumer_Tests
{
public class driver
{
public static IWebDriver Instance { get; set; }
public static void InitializeChrome()
{
Instance = new ChromeDriver(#"C:\Users\richard.cariven\Documents\Visual Studio 2015\Drivers\Chrome");
Instance.Manage().Window.Position = new System.Drawing.Point(2192, -963);
Instance.Manage().Window.Maximize();
Instance.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(10));
}
public static void InitializeFireFox()
{
Instance = new FirefoxDriver();
Instance.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(10));
}
public static string BSusername = "xxxxxxxxxxx";
public static string BSpassword = "xxxxxxxxxxx";
public static void InitialiseBrowserstack()
{
IWebDriver driver;
DesiredCapabilities caps = new DesiredCapabilities();
//caps.SetCapability("name", TestContext.TestName);
caps.SetCapability("browser", "IE");
caps.SetCapability("browser_version", "11.0");
caps.SetCapability("os", "Windows");
caps.SetCapability("os_version", "10");
caps.SetCapability("resolution", "1024x768");
caps.SetCapability("browserstack.user", BSusername);
caps.SetCapability("browserstack.key", BSpassword);
driver = new RemoteWebDriver
(new Uri("http://hub-cloud.browserstack.com/wd/hub/"), caps);
Instance = driver;
}
public static void refresh()
{
Instance.Navigate().Refresh();
}
public static void Quit()
{
Instance.Quit();
}
}
}
CBT Class - Set up to pick each Cross Browser testing Parameter
namespace Kukd_Consumer_Tests
{
public class CBT_driver
{
public static IWebDriver Instance { get; set; }
public static string CBTusername = "xxxxxxxx";
public static string CBTpassword = "xxxxxxxxxx";
public static void InitialiseChromeCBT(string testName)
{
IWebDriver driver;
var caps = new DesiredCapabilities();
caps.SetCapability("name", testName);
caps.SetCapability("build", "1.0");
caps.SetCapability("browser_api_name", "Chrome56x64");
caps.SetCapability("os_api_name", "Win8");
caps.SetCapability("screen_resolution", "1366x768");
caps.SetCapability("record_video", "true");
caps.SetCapability("record_network", "true");
caps.SetCapability("username", CBTusername);
caps.SetCapability("password", CBTpassword);
driver = new RemoteWebDriver
(new Uri("http://hub.crossbrowsertesting.com:80/wd/hub"), caps);
Instance = driver;
}
public static void InitialiseFFCBT()
{
IWebDriver driver;
var caps = new DesiredCapabilities();
caps.SetCapability("name", "test name");
caps.SetCapability("build", "1.0");
caps.SetCapability("browser_api_name", "FF46x64");
caps.SetCapability("os_api_name", "Win8");
caps.SetCapability("screen_resolution", "1366x768");
caps.SetCapability("record_video", "true");
caps.SetCapability("record_network", "true");
caps.SetCapability("username", CBTusername);
caps.SetCapability("password", CBTpassword);
driver = new RemoteWebDriver
(new Uri("http://hub.crossbrowsertesting.com:80/wd/hub"), caps);
Instance = driver;
}
public static void InitialiseIECBT(string testName)
{
IWebDriver driver;
var caps = new DesiredCapabilities();
caps.SetCapability("name", testName);
caps.SetCapability("build", "1.0");
caps.SetCapability("browser_api_name", "IE10");
caps.SetCapability("os_api_name", "Win8");
caps.SetCapability("screen_resolution", "1366x768");
caps.SetCapability("record_video", "true");
caps.SetCapability("record_network", "true");
caps.SetCapability("username", CBTusername);
caps.SetCapability("password", CBTpassword);
driver = new RemoteWebDriver
(new Uri("http://hub.crossbrowsertesting.com:80/wd/hub"), caps);
Instance = driver;
}
}
}
So what I need to be able to do is, in my common test so it applies to every test, loop through each of my Browsers/CBT Environments for all tests.
Am currently set up using NUnit (changed from MSTest because I have read it is easier to do this kind of thing in NUnit)
Any advice greatly appreciated, I have been advised that because I have used so many statics in my tests this may not be possible.
Regards
Richard
After a lot of searching and investigation I have decided to scrap my current framework and rewrite it using Xunit and a Factory Model. Once I have got this structure completed it should be easier to maintain and less brittle in future :)
I am automating my github profile and Following are my test cases:
Load Browser (this is defined in testInitialize()
Load Url
Perform Login
Below is the code snippet:
namespace GitAutomationTest
{
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium.IE;
using OpenQA.Selenium.Remote;
using System;
[TestClass]
public class GitTest
{
private string baseURL = "https://github.com/login";
private RemoteWebDriver driver;
public TestContext TestContext { get; set; }
[TestMethod]
public void LoadURL() {
driver.Navigate().GoToUrl(baseURL);
Console.Write("Loaded URL is :" + baseURL);
}
[TestMethod]
public void PerformLogin() {
driver.FindElementById("login_field").SendKeys("USERNAME");
driver.FindElementById("password").SendKeys("PASSWORD");
Console.Write("password entered \n ");
driver.FindElementByClassName("btn-primary").Click();
driver.GetScreenshot().SaveAsFile(#"screenshot.jpg", format: System.Drawing.Imaging.ImageFormat.Jpeg);
Console.Write("Screenshot Saved: screenshiot.jpg");
}
[TestCleanup()]
public void MyTestCleanup()
{
driver.Quit();
}
[TestInitialize()]
public void MyTestInitialize()
{
driver = new InternetExplorerDriver();
driver.Manage().Window.Maximize();
Console.Write("Maximises The window\n");
driver.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(20));
}
}
}
OUTPUT
Everytime I run all tests:
- Test is initialized : the internet explorer is loaded
- The base url is loaded
- Then the driver quits with TestCleanUP()
Next time the driver runs testperformLogin()
- The test cannot find the username and password elements to perform login, because the base url is not loaded this time.
How can we manage the TestInitialize() class such that:
- browser is up with baseurl until all the tests are completed.
How can we manage TestCleanup() such that:
- browser closes only after all the test are completed.
There is a AssemblyCleanup attribute which runs after all the tests are executed.
You can find more info on attributes here - Unit Testing Framework.
You need to move following code to "PerformLogin" test method
driver.Navigate().GoToUrl(baseURL);
OR another approach is to add following code at in "Mytestinitialize" method and remove "LoadURL" method
driver.Navigate().GoToUrl(baseURL);
You are facing the issue since [TestInitialize] is called before every [TestMethod] and [TestCleanup] is called after every [TestMethod].
In your case "LoadURL" test is able to get the URL but "PerformLogin" is not able to get the URL since it is not mentioned in "MyTestInitialize".