Postal.NET Revisited

Some of you may be aware of my Postal.NET project. It is an open-source library for writing decoupled applications that is available in GitHub and in Nuget. I already blogged about it before.

I recently updated it so that it targets .NET Standard 2.0 and also fixed the namespaces for its companion projects so that they are all under PostalNET. Current version for all projects is 1.2.0.

In a nutshell, Postal.NET publishes messages to channels and topics, either synchronously or asynchronously, and interested parties can subscribe to these.

Besides the core Postal.NET project, there are a few others:

  • PostalConventions.NET: configurable conventions for channels and topics
  • PostalCqrs.NET: a Command-Query Responsibility Segregation library built on top of Postal.NET
  • PostalInterceptor.NET: interception for message publishing
  • PostalRX.NET: Reactive Extensions
  • PostalRequestResponse.NET: a request-response wrapper
  • PostalWhen.NET: “when this, do that”

I still need to write unit tests, but there are many samples available that hopefully will be enough to get you started. If you have interest, please have a look and share your thoughts, either here or by creating issues in GitHub!

User Interface Unit Tests with .NET Core

In a previous post I talked about doing unit tests with .NET Core. What I didn’t cover was unit testing for the user interface (UI). It is actually something quite common, and we will see how we can do it now.

Selenium is a portable software-testing framework for web applications and there is a .NET port of it. We will be using the Selenium.WebDriver package, plus one or more of the following, to target different browsers:

Selenium offers a “minimum” contract that works across all browsers.

I won’t go through all of it, but I will give you some examples on how it works. We start by instantiating a driver:

using (var driver = (IWebDriver) new ChromeDriver(Environment.CurrentDirectory))
{
//...
}
Notice the Environment.CurrentDirectory parameter; it specifies the path where the driver can find the chromedriver.exe file, or geckodriver.exe for Firefox or MicrosoftWebDriver.exe, in the case of IE/Edge. These executables are added automatically by the Nuget packages. If you don’t dispose of the driver, the window will remain open after the unit test finishes. You can also call Quit at any time.
Now, we can navigate to some page:
driver
.Navigate()
.GoToUrl("http://www.google.com");
And find some element from its name:
var elm = driver.FindElement(By.Name("q"));
Besides the name, we can also search by:
  • Id: By.Id
  • CSS class: By.ClassName
  • CSS selector: By.CssSelector
  • Tag name: By.TagName
  • Link text: By.LinkText
  • Partial link text: By.PartialLinkText
  • XPath: By.XPath

Once we find an element, we can access its properties:

var attr = elm.GetAttribute("class");
var css = elm.GetCssValue("display");
var prop = elm.GetProperty("enabled");

Then we can send it text strokes:

elm.SendKeys("asp.net core");

Or click on it:

elm.Click();
As we know, page loading can take some time, so, we can configure the default time to wait for it, probably before we do a GoToUrl:
var timeouts = driver.Manage().Timeouts();
timeouts.ImplicitWait = TimeSpan.FromSeconds(1);
timeouts.PageLoad = TimeSpan.FromSeconds(5);
ImplicitWait is just a time that Selenium waits before searching for an element.
If we need to wait for some period of time, like, until some AJAX request finishes, we can do this:
var waitForElement = new WebDriverWait(driver, TimeSpan.FromSeconds(5));

var logo = waitForElement.Until(ExpectedConditions.ElementIsVisible(By.Id("hplogo")));
The condition passed to ExpectedConditions can be one of:
  • AlertIsPresent
  • AlertState
  • ElementExists
  • ElementIsVisible
  • ElementSelectionStateToBe
  • ElementToBeClickable
  • ElementToBeSelected
  • FrameToBeAvailableAndSwitchToIt
  • InvisibilityOfElementLocated
  • InvisibilityOfElementWithText
  • PresenceOfAllElementsLocatedBy
  • StalenessOf
  • TextToBePresentInElement
  • TextToBePresentInElementLocated
  • TextToBePresentInElementValue
  • TitleContains
  • TitleIs
  • UrlContains
  • UrlMatches
  • UrlToBe
  • VisibilityOfAllElementsLocatedBy
As you can see, you have a wealth of conditions that you can use. If the condition is not met before the timer expires, then the value returned by Until is null.
This can be a nice complement to your unit tests. Hope you find this useful! Winking smile