xUnit and White test failure cleanup - c#

I am beginning to look into using White UI testing with XUnit.
The basic structure for my tests is
Open the application
Test Something
Close the application
This works really well when test passes. However, when a test fails, the application is not closed. If multiple tests fail, this leads to lots of opened instances of my application.
To get around this, I use try and finally blocks but it is not very nice.
Is there an alternate option which achieves the same cleanup behaviour but looks a bit nicer? Like a "RunOnAssertFail" method?
[Fact]
public void MainWindowCreated()
{
bool testFailed = false;
Application application = Application.Launch(#"C:\Program\Program.exe");
Window mainWindow = GetWindow(application, "MainWidndow", 500);
try
{
testFailed = true;
mainWindow.Should().NotBe(null, ". Main Widndow could not be found");
testFailed = false;
}
finally
{
if (testFailed)
{
application.Close();
}
}
/*
* Rest of test case
*/
application.Close();
}
private static Window GetWindow(Application application,
string windowName,
int timeoutAfterMilliseconds)
{
Window window = null;
try
{
window = Retry.For(
() => application.GetWindows().First(
windowX => windowX.Title.Trim().Equals(windowName.Trim())),
TimeSpan.FromMilliseconds(timeoutAfterMilliseconds));
}
catch (InvalidOperationException)
{
}
return window;
}
Requires xUnit, White and Fluent Assertions to run.

After playing around I realised the assertions were it was throwing an exception and not actually asserting.
Therefore to help tidy it up, a try catch block is more appropriate
try
{
mainWindow.Should().NotBeNull("because this window is required for the rest of the test");
}
catch(XunitException)
{
application.Close();
throw;
}
However, this is still not ideal.

What about implementing IDisposable on your test class and use that to clean up?

Related

C# Unit test not waiting for app to close before proceeding to next unit test class

Using MSTest I have six unit test classes. I need an app (SolidWorks) to start from scratch for each test. No problem, I have the following in my unit test class to start and stop SolidWorks before the class starts and after the class finishes:
[ClassInitialize()]
public static void MyClassInitialize(TestContext testContext)
{
var progId = "SldWorks.Application";
var progType = System.Type.GetTypeFromProgID(progId);
app = System.Activator.CreateInstance(progType) as ISldWorks;
app.Visible = true;
DocumentSpecification documentSpecification;
documentSpecification = (DocumentSpecification)app.GetOpenDocSpec(fullFilePath);
documentSpecification.DocumentType = (int)swDocumentTypes_e.swDocPART;
var result = app.OpenDoc7(documentSpecification);
if (result == null)
{
throw new Exception("Couldn't load SOlidworks test file.");
}
}
[ClassCleanup()]
public static void MyClassCleanup()
{
if (app != null)
{
app.CloseAllDocuments(true);
app.ExitApp();
}
}
My problem is that when UnitTestClass1 gets finished UnitTestClass2 starts before SolidWorks is finished closing. UnitTestClass2 seems to be grabbing the SolidWorks process that was started in UnitTestClass1. I tried adding Thread.Sleep:
[ClassCleanup()]
public static void MyClassCleanup()
{
if (app != null)
{
app.CloseAllDocuments(true);
app.ExitApp();
Thread.Sleep(5000);
}
}
That didn't seem to work.
I tried a while loop to wait for Solidworks to close and that seems to hang.
If I run each unit test class one by one they all run fine and pass. Run as a group some of them fail because they are testing against the wrong environment (the file from the last test is still open).
How to make sure the next unit test doesn't run before the app is closed from the last unit test?
The behavior I want is for SolidWorks to run at the beginning of the class, run all the tests in the class and then for SolidWorks to close at the end of the class. I want this to happen for each class.

Selenium C# continue on failure

I'm trying to learn automation with Selenium Webdriver using c#. I have my custom method Assert. What I did to continue the test after catching an AssertFailedException is using try-catch below is my code
public static void assert(string value, IWebElement element)
{
try
{
Assert.AreEqual(value, element.Text);
}
catch (AssertFailedException e)
{
Console.WriteLine(e.Message.ToString());
}
}
My problem is it catches all AssertFailedException(which is my goal) but the result of the test is PASSED in visual studio. My question is, how do I implement Continue on Failure and Fail the test if the Console contains Exceptions. Thankyou in advance guys!
As far as I understand, you want to do several checks inside your test, and at the very end of it to determine whether any of of them failed. You may need to write some custom code to achieve this. For example, you may introduce a class Assertion:
internal class Assertion
{
private readonly string title;
private readonly object expected;
private readonly object actual;
public Assertion(string title, object expected, object actual)
{
this.title = title;
this.expected = expected;
this.actual = actual;
}
public bool IsMatch()
{
return this.actual == this.expected;
}
public override string ToString()
{
return $"Title: {title}. Expected: {expected}. Actual: {actual}";
}
}
When your test is running, you will create new instances of Assertion class and store them in a list. At the end of the test, you can use the following method:
private static void VerifyAssertions(Assertion[] assertions)
{
var failedAssertions = assertions.Where(a => !a.IsMatch()).ToArray();
if (failedAssertions.Any())
{
throw new AssertFailedException(string.Join<Assertion>("; ", failedAssertions));
}
}
You could try using verify instead of assert for minor checks. Assert by default indicates a major checkpoint and script execution will be terminated on fail and if you catch that exception the reporting will be ignored - this is expected behaviour. However, a verify indicates that the script can continue even on fail - in this case the failed step will be reported and the script will continue.
To put it simply, use assert when you don't want the script to proceed on failure and use verify when you want the script to report the failure and proceed.

Waiting for a frame to load using Selenium

I have seen many posts on handling switching between frames in Selenium but they all seem to reference the Java 'ExpectedConditions' library for the below method.
ExpectedConditions.frameToBeAvailableAndSwitchToIt
I was wondering if there is any C# implementation anywhere or if anyone has any such work around?
Cheers
There isn't a direct equivalent in the C# bindings but it's very easy to do this yourself.
Remember that Selenium is open source so let's dig out the source code. Here is the Java ExpectedConditions and here is the C# set.
So what's the Java version doing? Well, not a lot I tell you.
try {
return driver.switchTo().frame(frameLocator);
} catch (NoSuchFrameException e) {
return null;
}
All it's doing is attempting to switch to the frame you tell it to, and providing it was successful (as in, there was no exception in attempting to do that), then it's assumed it can carry on.
So, all you'll need to do is do the same thing in C#, so something like (not compiled):
public static Func<IWebDriver, bool> WaitUntilFrameLoadedAndSwitchToIt(By byToFindFrame)
{
return (driver) =>
{
try
{
return driver.SwitchTo().Frame(driver.FindElement(byToFindFrame));
}
catch (Exception)
{
return null;
}
return true;
};
}
As in, keep the same concept: try to find the frame and switch to it, any exceptions then we return null and force the caller (usually a WebDriverWait instance) to iterate through again. Returning true will tell the caller that we are happy we can move on.
All the waiting & expected conditions classes live in the OpenQA.Selenium.Support.UI namespace which lives in the WebDriver.Support.dll assembly.
These answers are old and I had the same issue. I was able to use SeleniumExtras.WaitHelpers.ExpectedConditions from nuget to achieve this easily.
//wait for 10 seconds max for the frame
WebDriverWaitwait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
wait.Until(SeleniumExtras.WaitHelpers.ExpectedConditions.FrameToBeAvailableAndSwitchToIt(By.Id("FRAMEID")));
I have just committed such a ugly code. Dropping here for the future!
protected void SwitchToFrame(int iframe = 1)
{
var driver = GetWebDriver();
driver.SwitchTo().DefaultContent();
bool done = false, timeout = false;
int counter = 0;
do
{
counter++;
try
{
driver.SwitchTo().Frame(iframe);
done = true;
}
catch (OpenQA.Selenium.NoSuchFrameException)
{
if (counter <= Constants.GLOBAL_MAX_WAIT_SEC)
{
Wait(1);
continue;
}
else timeout = true;
}
} while (!done && !timeout);
if (timeout) throw new OpenQA.Selenium.NoSuchFrameException(iframe.ToString());
}

How should I ask for user input from a background thread?

I'm using an external library load a large and complex file. The call(s) to this library are fairly complex, so I've wrapped them in a couple of static helper methods which nicely take care of caching etc. for me. These methods are then run in the background using Tasks.
During the load process, the library will in some cases throw an Exception stating that a block of the file is malformed and therefore cannot be parsed. These Exceptions are considered "safe", and, if they're swallowed, the library will skip the bad block and happily continue to parse the rest of the file.
When this occurs, I need to show the user a dialog box asking whether or not the file import should be aborted. This works fine as follows:
public static class MyBigFileLoadMethods {
// private fields for locking, caching, etc.
public static Load(string filePath, bool cache = true) {
// validation etc.
try {
var data = LoadMethodInDll(filePath);
} catch (BadBlockException) {
if (MessageBox.Show("boom. continue anyway?") == DialogResult.Yes) {
// call appropriate dll methods to ignore exception and continue loading
} else {
throw;
}
}
}
}
Calling MessageBox.Show() from a method that was designed to be run way in the background feels very wrong, but I haven't come up with a better way that didn't involve so much marshaling and invoking that the code became very difficult to read. Is there a cleaner way to do this or a better way to me to design my loading process?
The appropriate way for a library to do this is via some kind of callback. The simplest implementation would be a delegate returning a bool indicating whether processing should continue. A richer but complicated way would be a policy interface with various methods to implement indicating whether to continue, abort, retry, etc.
Then your UI code provides the callback that shows a message to the user in an appropriate way. Your code to load the library will look like this:
public static class MyBigFileLoadMethods {
// private fields for locking, caching, etc.
public static void Load(string filePath, Func<Exception, bool> continueOnException = null, bool cache = true) {
// validation etc.
try {
var data = LoadMethodInDll(filePath);
} catch (BadBlockException e) {
if (continueOnException != null && continueOnException(e)) {
// call appropriate dll methods to ignore exception and continue loading
} else {
throw;
}
}
}
}
Then in your UI code you will want to marshal back to the UI thread. It will look something like this:
MyBigFileLoadMethods.Load("C:\path\to\data", ShowError);
private bool ShowError(Exception e)
{
if (this.InvokeRequired)
{
return (bool)this.Invoke(new Func<Exception, bool>(ShowError), e);
}
return MessageBox.Show(string.Format("boom: {0}. continue anyway?", e.Message)) == DialogResult.Yes;
}

How do I check "no exception occurred" in my MSTest unit test?

I'm writing a unit test for this one method which returns "void". I would like to have one case that the test passes when there is no exception thrown. How do I write that in C#?
Assert.IsTrue(????)
(My guess is this is how I should check, but what goes into "???")
I hope my question is clear enough.
Your unit test will fail anyway if an exception is thrown - you don't need to put in a special assert.
This is one of the few scenarios where you will see unit tests with no assertions at all - the test will implicitly fail if an exception is raised.
However, if you really did want to write an assertion for this - perhaps to be able to catch the exception and report "expected no exception but got this...", you can do this:
[Test]
public void TestNoExceptionIsThrownByMethodUnderTest()
{
var myObject = new MyObject();
try
{
myObject.MethodUnderTest();
}
catch (Exception ex)
{
Assert.Fail("Expected no exception, but got: " + ex.Message);
}
}
(the above is an example for NUnit, but the same holds true for MSTest)
In NUnit, you can use:
Assert.DoesNotThrow(<expression>);
to assert that your code does not throw an exception. Although the test would fail if an exception is thrown even if there was no Assert around it, the value of this approach is that you can then distinguish between unmet expectations and bugs in your tests, and you have the option of adding a custom message that will be displayed in your test output. A well-worded test output can help you locate errors in your code that have caused a test to fail.
I think it's valid to add tests to ensure that your code is not throwing exceptions; for example, imagine you are validating input and need to convert an incoming string to a long. There may be occasions when the string is null, and this is acceptable, so you want to ensure that the string conversion does not throw an exception. There will therefore be code to handle this occasion, and if you haven't written a test for it you will be missing coverage around an important piece of logic.
This helper class scratched my itch with MSTest. Maybe it can scratch yours also.
[TestMethod]
public void ScheduleItsIneligibilityJob_HasValid_CronSchedule()
{
// Arrange
var factory = new StdSchedulerFactory();
IScheduler scheduler = factory.GetScheduler();
// Assert
AssertEx.NoExceptionThrown<FormatException>(() =>
// Act
_service.ScheduleJob(scheduler)
);
}
public sealed class AssertEx
{
public static void NoExceptionThrown<T>(Action a) where T:Exception
{
try
{
a();
}
catch (T)
{
Assert.Fail("Expected no {0} to be thrown", typeof(T).Name);
}
}
}
Don't test that something doesn't happen. It's like assuring that code doesn't break. That's sort of implied, we all strive for non-breaking, bug-less code. You want to write tests for that? Why just one method? Don't you want all your methods being tested that they don't throw some exception? Following that road, you'll end up with one extra, dummy, assert-less test for every method in your code base. It brings no value.
Of course, if your requirement is to verify method does catch exceptions, you do test that (or reversing it a bit; test that it does not throw what it is supposed to catch).
However, the general approach/practices remain intact - you don't write tests for some artificial/vague requirements that are out of scope of tested code (and testing that "it works" or "doesn't throw" is usually an example of such - especially in scenario when method's responsibilities are well known).
To put it simple - focus on what your code has to do and test for that.
I like to see an Assert.Whatever at the end of each test, just for consistency... without one, can I really be sure there's not supposed to be one there?
For me, this is as simple as putting Assert.IsTrue(true);
I know I didn't accidentally put that code in there, and thus I should be confident enough at quick a skim through that this was as intended.
[TestMethod]
public void ProjectRejectsGappedVersioningByDefault() {
var files = new List<ScriptFile>();
files.Add(ScriptProjectTestMocks.GetVersion1to2());
files.Add(ScriptProjectTestMocks.GetVersion3to4());
Assert.Throws<ScriptProject.InvalidProjectFormatException>(() => {
var sut = new ScriptProject(files);
});
}
[TestMethod]
public void ProjectAcceptsGappedVersionsExplicitly() {
var files = new List<ScriptFile>();
files.Add(ScriptProjectTestMocks.GetVersion1to2());
files.Add(ScriptProjectTestMocks.GetVersion3to4());
var sut = new ScriptProject(files, true);
Assert.IsTrue(true); // Assert.Pass() would be nicer... build it in if you like
}
My friend Tim told me about ExpectedException. I really like this b/c it is more succinct, less code, and very explicit that you are testing for an exception.
[TestMethod()]
[ExpectedException(typeof(System.Exception))]
public void DivideTest()
{
int numerator = 4;
int denominator = 0;
int actual = numerator / denominator;
}
You can read way more about it here: ExpectedException Attribute Usage.
With Xunit you can use this:
var exception = Record.Exception(() =>
MethodUnderTest());
Assert.Null(exception);
or for async operations
var exception = await Record.ExceptionAsync(async () =>
await MethodUnderTestAsync());
Assert.Null(exception);
Another way which worked for me is to store it in a variable and check output.
var result = service.Run()
Assert.IsFalse(result.Errors.Any())
using Moq;
using Xunit;
[Fact]
public void UnitTest_DoesNotThrow_Exception()
{
var builder = new Mock<ISomething>().Object;
//Act
var exception = Record.Exception(() => builder.SomeMethod());
//Assert
Assert.Null(exception);
}

Categories