Search

Categories

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Send mail to the author(s) E-mail

# Thursday, April 24, 2014

Ctrl+Shift+/ - block comment html

| | # 
# Wednesday, April 23, 2014
( BDD )

Wiring up the creation of Stories

image
Here is the CRUD interface that MVC scaffolding did for us – notice the Enum in StoryType.  It only accepts the correct type (but of course should be a drop down)

image
Woo – front end using the service!!

Front end validation is working (ie javascript on the required fields).

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "ID,Title,Content,Rating,CreatedAt,StoryType")] Story story) {
    if (ModelState.IsValid) {
        // new up the StoryApplication
        var app = new StoryApplication(title: story.Title, content: story.Content, storyType: story.StoryType);

        // call our StoryCreator service
        var sc = new StoryCreator();
        StoryCreatorResult result = sc.CreateNewStory(app);

        //db.Stories.Add(story);
        //db.SaveChanges();
        if (result.StoryApplication.IsValid())
            return RedirectToAction("Index");
    }

    return View(story);
}

Simplest thing possible to get working – so only if the storyapp is valid, does it go back to the index.  Doesn’t display why yet.  Makes more sense for the view to display the StoryApplication, as this is more of a ViewModel.

image
Using the new EnumDropDownList in MVC5.1

| | # 
# Tuesday, April 15, 2014

gpresult /V

When you want to find out what groups you're a member of.

| | # 
# Thursday, April 10, 2014
( Git )

Using Staging to try to only commit important bits

Not using branches yet

pushing to a named shared directory on remote server

| | # 
# Wednesday, April 09, 2014
( BDD )

Refactoring around validation so methods are short.

How to do data access – Repository, UoW etc..

  • UoW – EF uses, nHibernate made it popular
    • create a context or session
    • get objects from or add object to session
    • save changes transactionally when done
  • Repository
    • eg repo.GetUser(ID)
    • problem: lots of methods
  • CQRS (Command Query Separation)
    • problem: confusing
  • IRepo<T> – Mix UoW and Repo
    • not transactional
    • only works with 1 class
    • returns iqueryable which breaks encapsulation
    • needless overhead

SImplest thing – just use EF as it is intended..UoW

namespace Funny.DB {
    public class Session : DbContext {
        public Session()
            : base(nameOrConnectionString: "Funny") {
            // Nice for development
            Database.SetInitializer(new DropCreateDatabaseIfModelChanges<Session>());
        }
        public DbSet<Story> Stories { get; set; }
    }
}

Added EF6 to both projects.  Then add a folder called DB then class called Session are wire up.

Don’t default strings to nvarchar(max)

image
Great test just spiking out a console app and writing to the db.  Using ObjectExplorer in VS is handy too.

<connectionStrings>
  <add name="Funny" providerName="System.Data.SqlClient" connectionString="server=.\sqlexpress;database=Funny;integrated security=true" />
</connectionStrings>

EF Migrations / Testing

// Part 2
public Story ApplicationAccepted() {
    Story story = new Story();
    using (var session = new Session()) {
        // Create Story from CurrentStory
        story.Title = CurrentApplication.Title;
        story.Content = CurrentApplication.Content;
        story.Rating = CurrentApplication.Rating;
        story.CreatedAt = DateTime.Now;
        story.StoryType = CurrentApplication.StoryType;

        session.Stories.Add(story);
        session.SaveChanges();
    }
    return story;
}

Simple way of adding a Story to the session/context then saving the UoW.
image
From the rails world, a _Test database which the tests write to. Data was written by tests.

class Program {
    static void Main(string[] args) {
        var session = new Session();
        var story = new Story { Title = "Stick5" };
        session.Stories.Add(story);

        var vote = new Vote { Story=story, RatingChange = 1, CreatedAt = DateTime.Now };
        session.Votes.Add(vote);
        session.SaveChanges();

        foreach (var sto in session.Stories) {
            Console.WriteLine(sto.Title);
            if (sto.Votes != null) {
                var vot = sto.Votes.FirstOrDefault();
                Console.WriteLine(vot.RatingChange);
            }
        }

        Console.WriteLine("Done!");
        Console.Read();
    }
}

Spiking out a new entity called Vote.  A Story can have many Votes.  Did a pre TDD spike to make sure EF is wired up correctly and DB changes are being written.

3:18 of 4:10

Alt S W T – Test Explorer shortcut

public void Dispose() {
    //new Session().Database.ExecuteSqlCommand("DELETE FROM Votes");
    new Session().Database.ExecuteSqlCommand("DELETE FROM Stories");
}

Implementing IDisposable on ValidStoryReceived tests
private bool TitleAlreadyExists() {
    bool exists;
    using (var session = new Session()) {
        exists = session.Stories.FirstOrDefault(s => s.Title == CurrentApplication.Title) != null;
    }
    return exists;
}

FirstOrDefault and not Where, as then null check gets confused.

Unique constraints add to database?

namespace Funny.DB {
    public class Session : DbContext {
        public Session()
            : base(nameOrConnectionString: "Funny") {
            // Nice for development
            //Database.SetInitializer(new DropCreateDatabaseIfModelChanges<Session>());
        }
        public DbSet<Story> Stories { get; set; }
        public DbSet<Vote> Votes { get; set; }
    }
}

Enable-Migrations –EnableAutomaticMigrations
Update-Database –Force (when want to delete data too)

Moved to localdb (new improved sqlexpress!)

A Good API

And an interface too so can mock out if need to?

Do we need another layer of abstraction currently? Hmm – lets get it working in MVC first.  Easiest thing to do is to add another project and then reference.

image
Added a reference to Funny project.  The only service I have currently is StoryCreator, so that’s what I’ll try to wire up.

image
Right click on controllers, and add a controller with views (telling it where the story model and db context are)

image
After updating EF in the web project, commenting out System.Data (EF6 namespace change), and putting in a connection string, I can view data!

Update all Packages and Visual Studio

Updating all.. noticing that startup time for MVC5 / EF6 project is quite slow especially when hitting the db for the first time.

Where to Now?

Summary so far – have got a testable ‘Creator’ of Stories.  So lets try to wire this up to our MVC creation of stories from the scaffolding.

| | # 
# Wednesday, April 02, 2014
( BDD | Funny )

The third iteration of the British Humour / Funny website

image

image

  • First iteration (shown above – Winter)
    • Generic repository
    • EF CodeFirst
    • Fakes
    • Unity
    • IValidatableObject
  • Second iteration (below - Humour)
    • Based on Imar’s work
    • Heavy
    • Never got it into production

image

What Are We Doing?

  • Webapp to display ‘Stories’ ie jokes/video/quote/pictures/animated gif
  • CRUD form for administrator
  • BDD style of development
  • KISS
    • Real code that I intend to use
    • Not overly complicate

Setup

  • xUnit
  • FluentAssertions
  • GitHub put source onto

Features

Category of things that an application does.  A business critical feature ie not engineering eg Mailers.  Something that’s going to deliver some value

  • Authentication
  • Registration
  • Reminders

Funny:

  • Display
  • CRUD

BDD

  • Feature
  • Scenario (context) – class
  • Spec (test) – method

BDD – Gauging how our application behaves

Unit Testing – Isolated functionality of app returns what is expected

image
Unit test.. not BDD..

image
BDD – What happens when I do this approach.  Specify how the application works in the eyes of a user.

Send tests to manager as a screenshot… Is this what you mean?

‘Should’ ambiguous

[Trait("User visits the Homepage", "")]
public class VisitHomepage {
    [Fact(DisplayName="Show list of Stories in rank order")]
    public void ShowListOfStoriesInRankOrder() {
        throw new NotImplementedException();
    }
    [Fact(DisplayName = "Log entry is created")]
    public void LogEntryIsCreated() {
        throw new NotImplementedException();
    }
}

image
First shot at creating BDD tests for my app.

BDD Philosophy

Dan North in March 2006

..”Programmers wanted to know where to start, what to test and what not to test, how much to test in one go, what to call their tests, and how to understand why a test fails.”

Telling stories with our tests.

Given, When, Then…

as a, i want, so that

what value to end user..test should show

BDD is a user-oriented way to structure tests and organise development

Takes great effort and patience to get right.

Test Naming

[Trait("Anon User visits the Homepage", "")]
public class VisitHomepage {
    [Fact(DisplayName="Show list of all Stories in rank order")]
    public void ShowListOfStoriesInRankOrder() {
        throw new NotImplementedException();
    }
    [Fact(DisplayName = "Log entry is created")]
    public void LogEntryIsCreated() {
        throw new NotImplementedException();
    }
}

Spec (test) name - how our code responds to Scenario (class)

2:46 of 6:14.. look for other Rob Conery MVC BDD tests.. others test names

CRUD

namespace Specs.CRUD {
    public class Story {

    }

    [Trait("A Valid Story is submitted", "")]
    public class ValidStoryReceived {
        [Fact(DisplayName = "A Story is added to the system")]
        public void StoryAddedToSystem() {
            throw new NotImplementedException();
        }

        [Fact(DisplayName = "A confirmation message is shown to the administrator")]
        public void ConfirmationMessage() {
            throw new NotImplementedException();
        }
    }
}

Creating classes inline with tests to begin with – Brad Wilson inspired.

Validation

public class StoryCreatorResult {
    public Story NewStory { get; set; }
    public string Message { get; set; }
    public bool Success { get; set; }
    public StoryApplication StoryApplication { get; set; }

    public StoryCreatorResult() {
        this.Success = false;
    }
}

public class StoryCreator {
    public StoryApplication ValidateApplication(StoryApplication app) {
        // do some stuff
        app.HasBeenValidated = true;
        return app;
    }

    public StoryCreatorResult CreateNewStory(StoryApplication app) {
        var result = new StoryCreatorResult();

        // validation
        result.StoryApplication = ValidateApplication(app);

        // Successful creation of story!
        result.NewStory = new Story();
        result.Message = "Successfully created a new story!";
        result.StoryApplication = app;

        return result;
    }
}


StoryCreator (Service layer)

  • takes in a StoryApplication
  • returns a StoryCreatorResult
    • NewStory (if it worked)
    • StoryApplication (with a HasBeenValidated flag)
    • Message
public enum StoryType {
    Joke,
    Video,
    Quote,
    Picture,
    AnimatedGIF
}

public class Story {
    public int ID { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }
    public int Rating { get; set; }
    public DateTime CreatedAt { get; set; }
    public StoryType StoryType { get; set; }

    public Story() {
        this.CreatedAt = DateTime.Now;
        this.StoryType = StoryType.Joke;
    }
}

Story currently has not much in it.
public class StoryApplication {
    public string Title { get; set; }
    public string Content { get; set; }
    public StoryType StoryType { get; set; }
    public bool HasBeenValidated { get; set; }

    public StoryApplication(string title, string content, StoryType storyType) {
        this.Title = title;
        this.Content = content;
        this.StoryType = storyType;
        this.HasBeenValidated = false;

        if (String.IsNullOrWhiteSpace(this.Title)
            || String.IsNullOrWhiteSpace(this.Content))
            throw new InvalidOperationException("Can't have an empty Title or Content");
    }
}

Interesting throwing on the StoryApplication if title or content are empty.  It should be handled gracefully on the client anyway so should never get to here.
[Trait("A StoryApplication is created with an empty Title or Content", "")]
public class EmptyTitle {
       
    [Fact(DisplayName = "An exception is thrown with empty title")]
    public void ApplicationInvalid() {
        Assert.Throws<InvalidOperationException>(
            () => new StoryApplication("", "content here", StoryType.Joke)
            );
    }

Testing the throw

image

2014-04-08 07.28.32
This helps a lot!

| | # 
# Monday, March 24, 2014
( BDD )

Goal: To fully understand the project, and take the ideas forward into my project

Problem: Got to a stage in his BDD Videos where tests not passing.

  • Take his code and get tests passing
  • Add more tests
  • Make overall diagram better
  • Get working within MVC5 – see grist off github link
  • Build out BritishHumour using same ideas
    • Videos again
    • Happy path first

Tests failing from GitHub

Needs data in UserMailerTemplates – had to call Update-Database to get the seed method to run.

| | # 
# Saturday, March 22, 2014
( BDD )

Email

Uses MarkdownSharp for html email.

Using file maildrop in c:\temp\maildrop

API

OpenAuth implemented!

Implement an interface so people can mock out if we want to .

In the past we’d do:

Public static Authenticate(arguments…)

Don’t want static methods as

  • Almost impossible to mock out

If we’re in an MVC app and want to mock out someone being authenticated… then statics wouldn’t work (without hitting the db).

Configuration

Allow us to pass in

  • Reset URL
  • ConfirmationURL
  • MinPasswordLength

Where to go from Here

Mocking videos

Controller/Filter/Integration/OWIN…

Test behaviour

  • Feature eg Registration, Authentication
  • Scenario (Context)  “What happens when I do this..”
  • Spec test

Clarity!

| | # 
# Thursday, March 20, 2014
( BDD )
  • Feature eg Registration, Authentication
  • Scenario (Context) eg ValidLogin, InvalidEmailOrPassword, EmptyEmailOrPassword.
  • Spec – test

image

Added specs to a new playlist

image

Created new: Authenticator, AuthenticationResult, Credentials classes

namespace Specs.Authentication {
    [Trait("Authentication", "Valid login")]
    public class ValidLogin {
        AuthenticationResult _result;
        public ValidLogin() {
            var auth = new Authenticator();
            _result = auth.AuthenticateUser(new Credentials { Email = "dave@dave.com", Password = "password" });
        }

        [Fact(DisplayName = "User authenticated")]
        public void AuthenticateTheUser() {
            Assert.True(_result.Authenticated);
        }

Going for happy path first!

Engineering the solution…

UoW issue in Authenticator when I want to pull something out ie a User, then write a UserSession if all email and password are fine.  Need to keep within the same UoW..or…

28:32 of 30:51

image

Refactor

public AuthenticationResult AuthenticateUser(Credentials creds) {
    _session = new Session();
    var result = new AuthenticationResult();
    User user = null;
    this.CurrentCredentials = creds;

    if (EmailOrPasswordNotPresent()) {
        result = InvalidLogin("Email and Password are required to login");
    } else {
        //find the user
        user = LocateUser();

        //if they're not here we're done
        if (user == null) {
            result = InvalidLogin("Invalid email or password");
            //does the password match?
        } else if (HashedPasswordDoesNotMatch(user)) {
            result = InvalidLogin("Invalid email or password");
            //success!
        } else {
            user.AddLogEntry("Login", "User logged in");
            CreateSession(user);

            result.Authenticated = true;
            result.User = user;
            result.Message = "Welcome! You are logged in";

            _session.SaveChanges();
        }
    }

    _session.Dispose();
    return result;
}

As need to reference the same session in 2 places

  • LocateUser (read from db)
  • CreateSession (write to db)

Have refactored it to be instantiated and disposed in the same controlled method.  So no early returns.

AuthenticateUserByToken – used for API stuff..just take a token and find the User.

Also put in more stuff here on Credentials…am leaving as hoping not to need it yet.

| | #