Search code examples
c#.netunit-testingseleniumnunit

Take screenshot on test failure + exceptions


Does any of you know possible solution for taking screenshots on test failures and exceptions?

I've added following code in TearDown() but as a result it also makes screenshots on passed tests, so it is not the best solution:

DateTime time = DateTime.Now;
string dateToday = "_date_" + time.ToString("yyyy-MM-dd") + "_time_" + time.ToString("HH-mm-ss");
Screenshot screenshot = ((ITakesScreenshot)driver).GetScreenshot();
screenshot.SaveAsFile((settings.filePathForScreenShots + "Exception" + dateToday + ".png"), System.Drawing.Imaging.ImageFormat.Png);

I've already found that idea: http://yizeng.me/2014/02/08/take-a-screenshot-on-exception-with-selenium-csharp-eventfiringwebdriver/, to use WebDriverExceptionEventArgs, but for some reasons it makes also some random screenshots without any reasonable explanation.

Other ideas I found are for Java and not for NUnit which I use with Selenium, so they are pretty useless.


Solution

  • If you put the screenshot logic in your TearDown method it will be called after each test finishes, no matter if it succeeded or failed.

    I use a base class that has a function which wraps the tests and catches all exceptions. When a test fails the exception is caught and a screenshot is taken.

    I use this base class for all my Selenium tests and it looks something like this:

    public class PageTestBase
    {
        protected IWebDriver Driver;
    
        protected void UITest(Action action)
        {
            try
            {
                action();
            }
            catch (Exception ex)
            {
                var screenshot = Driver.TakeScreenshot();
    
                var filePath = "<some appropriate file path goes here>";
    
                screenshot.SaveAsFile(filePath, ImageFormat.Png);
    
                // This would be a good place to log the exception message and
                // save together with the screenshot
    
                throw;
            }
        }
    }
    

    The test classes then look like this:

    [TestFixture]
    public class FooBarTests : PageTestBase
    {
        // Make sure to initialize the driver in the constructor or SetUp method,
        // depending on your preferences
    
        [Test]
        public void Some_test_name_goes_here()
        {
            UITest(() =>
            {
                // Do your test steps here, including asserts etc.
                // Any exceptions will be caught by the base class
                // and screenshots will be taken
            });
        }
    
        [TearDown]
        public void TearDown()
        {
            // Close and dispose the driver
        }
    }