Search

Categories

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Send mail to the author(s) E-mail

# Wednesday, May 13, 2015

Methods that return something…(Queries)

public string GetFileName(int id) { // This can never be null as int is a value type, and workingDirectory is a pre condition return Path.Combine(this.WorkingDirectory, id + ".txt"); }

Null is never a valid return value (a good design decision)

// Could return a null/empty string if 1) no message 2) exception is thrown public string Read(int id) { var path = this.GetFileName(id); if (!File.Exists(path)) throw new ArgumentException("bad path", "read"); var message = File.ReadAllText(path); return message; }
3 ways to approach this problem

Tester/Doer

public bool Exists(int id){ var path = GetFileName(id); return File.Exists(path); }

then

// client invokes string message = ""; if (fileStore.Exists(49)) message = fileStore.Read(49);

So, ok but not brilliant as need to know the idiom.  Also not thread safe

TryRead

| | # 

Robustness principle

  • Conservative in what you send (give good guarantees)
  • Liberal in what you accept
    • fail fast if can’t understand

Input

var fileStore = new FileStore();
fileStore.Save(42, “Hello world”); // Throws

As FilePath on the object is null.  So will fail/throw at runtime.

Could make an explicit constructor, so.

public FileStore(string workingDirectory) { // Guard clause as string is a ref type, so could be set to null outside if (workingDirectory == null) throw new ArgumentNullException("workingDirectory"); this.WorkingDirectory = workingDirectory; } // Private set public string WorkingDirectory { get; private set; }

Nullable References are Evil

Value types are primitive types like: ints, decimals, bools – non nullable by defaults

Ref types are Classes – nullable by default (non-nullable ref types not possible..language problem)

Fail Fast

// Exception messages are like documentation if (!Directory.Exists(workingDirectory)) throw new ArgumentException("You tried to supply a working directory string which doesn't exist." + " Please supply a valid path to an existing directory", "workingDirectory");

Be as tolerant as possible for inputs.

Be an explicit as possible about problems, and how to fix the problems.

| | # 
# Tuesday, May 12, 2015

http://www.pluralsight.com/courses/encapsulation-solid

Code that Sucks – many programmers in orgs feel their codebase does

Stand on the shoulders of giants (ie use ‘frameworks’ like ORMS etc..)

Make clearer code

public string Save(int id, string message) – what is the return string?? not obvious… need to read source

public void Read(int id).. why does this return void? need to read source

The Impact of Code that sucks

Long term productivity – a few weeks!!.. hard to write new features

Maintainability – if built up lots of technical debt

Encapsulation

  • Information hiding (Implementation hiding is a better name)
    • property / field.. eg password on a user class..maybe want to hide keeping an array of previous ones
  • protection of invariants
    • invalid states are difficult/impossible
    • assertions

Beyond OO

Command Query Separation (CQS) Principal

Bertand Meyer

CQRS – something different..architectural design pattern.. distributed architecture

Commands – have observable side effects eg send an email, write something to disk

Should do 1 or another

Query – returns data

Commands – returns void ie should do something

void Save(Order order); – what does it do? probably saves an order
void Send (T message) -
void Associate (IFoo foo, Bar bar);

All return void… so, it must have a side effect… so must be a command (otherwise what's the point)

Ok to invoke a queries eg

// Command
public void Save(int, id, string message)
{
  // GetFileName is a Query
  var path = this.GetFileName(id);
  File.WriteAllText(path, message);
}

Queries – return data (no side effects)

Do not mutate observable state

Order[] GetOrders(int userId); – probably gets orders associated with that userId
IFoo Map(Bar bar);
T Create(); – returns an instance of T

Idempotent – if invoke n times, it wont change the state of the system

If follow CQS can trust the codebase / easier to reason about the code without fully understanding the implementation details

http://blog.ploeh.dk/2014/08/11/cqs-versus-server-generated-ids/

| | # 
# Thursday, April 30, 2015

Base class

  • setup and teardown
  • login
  • waiting for some time
| | # 
# Wednesday, April 29, 2015

Interesting code:

[TestClass] public class LoginTests { [TestInitialize] public void Init() { // Singleton to make writing tests easier Driver.Initialize(); } [TestMethod] public void Admin_User_Can_Login() { LoginPage.GoTo(); LoginPage.LoginAs("dave").WithPassword("letmein").Login(); Assert.IsTrue(DashboardPage.IsAt, "Failed to login"); } [TestCleanup] public void CleanUp() { // Using our Driver class, so don't have to talk to IWebDriver directly (which has a Close method) Driver.Close(); } }

Then:

public class Driver { public static IWebDriver Instance { get; set; } public static void Initialize() { Instance = new FirefoxDriver(); Instance.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(5)); } public static void Close() { //Instance.Close(); } }

And:

public class LoginPage { public static void GoTo() { //Driver.Instance.Navigate().GoToUrl("http://localhost:46780/wp-login.php"); // work Driver.Instance.Navigate().GoToUrl("http://localhost:19461/wp-login.php"); // home } public static LoginCommand LoginAs(string userName) { return new LoginCommand(userName); } } public class LoginCommand { private readonly string userName; private string password; public LoginCommand(string userName) { this.userName = userName; } public LoginCommand WithPassword(string password) { this.password = password; // Returning the LoginCommand object return this; } public void Login() { var loginInput = Driver.Instance.FindElement(By.Id("user_login")); loginInput.SendKeys(userName); var passwordInput = Driver.Instance.FindElement(By.Id("user_pass")); passwordInput.SendKeys(password); var loginButton = Driver.Instance.FindElement(By.Id("wp-submit")); loginButton.Click(); } }

What to do with smoke tests?

  • Get it running at part of build process
  • Make sure developers can run it locally
| | # 
# Monday, April 27, 2015

http://www.pluralsight.com/courses/automated-testing-framework-selenium

Why BAT?

  • Regression “it worked yesterday!”
  • Absolute requirements
  • BATs test more production code with fewer lines of BAT code

Common Failure Points

  • Recorded brittle tests (it is fast… but something changes.. which causes things to break)
  • Not building a framework
  • Writing tests like code

Smoke testing… the widest tests… most basic functionality

The Page Pattern

A Class for each page (or section eg Header)
Methods for each piece of functionality/actions that a user can do

Basic Rules

  • Never require tests to declare variables
  • Never require tests to use new keyword
  • Never require tests to manage state
  • Never expose the browser or DOM to the tests or let them manipulate it directly
  • Always reduce the number of parameters for API calls
  • Always use default values instead of requiring parameters
  • Prefer to make the API easier to use over making the API less complex
  • Prefer enums and constants (ie restrict input values where possible)

Static Methods

Ok here..as optimising for ease of use over maintenance for the framework itself..

most of the time production code we are optimising for maintainability and understand ability, so don’t use Static methods.

Smoke Tests

Core functionality / basic things.. with wide brush strokes…simple.. to determine any major problems

  • Login
  • Create new post
  • Edit an existing page

Creating a Solution

Selenium WebDriver
Selenium WebDriver Support Classes

image
First test – launches a browser (FF is default) and test passes (there are no conditions)

public class Class1 { public void Go(){ var driver = new FirefoxDriver(); //driver.Navigate().GoToUrl("http://google.com"); driver.Navigate().GoToUrl("http://www.davestopmusic.com"); } }
| | # 
# Monday, April 20, 2015
( Spotify )

https://github.com/DanielLarsenNZ/Radiostr-SpotifyWebApi

Initial thoughts on his code

  • Tidy, and designed with lots of traditional comments
  • Async all the way (just use .Wait to make it sync)
  • Testable
    • HttpClient mocking out
  • ClientCredentialsAuthorizationApi
  • Caching
  • Defensive code checking for NullOrEmpty

Putting on a test Console App

image

Annoying that breakpoint is caught at top level.

image
Okay so I just need to break in VS!

| | # 
# Friday, April 17, 2015
( LSCC | Spotify )

Thanks to everyone who came last night - really appreciated the questions and laughter!!

http://www.meetup.com/london-software-craftsmanship/events/221749420/
https://skillsmatter.com/meetups/7134-software-craftsmanship-with-music-and-financial-trading

The soundtrack before the talk was:

image

An Elvis impersonator, covering dead people.  I really like this album
http://www.davestopmusic.com/Artists/Details/1W04ZWzAoPZ6eY754HgXQP

The Talk

www.davestopmusic.com  (main site – Amazon EC2)

dmusic.azurewebsites.net (test site - Azure)

https://ci.appveyor.com/project/djhmateer/davesmusic – Build / Test / Deploy to Azure

 

Code and presentation: https://github.com/djhmateer/davesmusic (I’ll put the HQ videos up there this weekend)

Music Discussed

Where to Next?

Got some great questions on testing which is making me think of where next..

| | # 
# Tuesday, April 14, 2015
( Spotify )

image

image
Doing anything that needs authorisation fails.

| | #