Creating a Go Module & Writing Tests in Less Than 3 Minutes

In this short (less than 4 minutes) video I put together a Go module library, then setup some first initial tests calling against functions in the module.

 

00:12 – Writing unit tests.

00:24 – Create the first go file.

00:40 – Creating the Go go.mod file. When creating the go.mode file, note the command is go mod init [repopath] where repopath is the actual URI to the repo. The go.mod file that is generated would look like this.

module github.com/adron/awesomeLib

go 1.13

00:56 Enabling Go mod integration for Goland IDE. This dialog has an option to turn off the proxy or go direct to repo bypassing the proxy. For more details on the Go proxy, check out goproxy.io and the Go docs for more details.

01:09Instead of TDD, first I cover a simple function implementation. Note the casing is very important in setting up a test in Go. The test function needs to be public, thus capitalized, and the function needs accessible, thus also capitalized. The function in the awesomeLib.go file, just to have a function that would return some value, looks like this.

package awesomeLib

func GetKnownResult() string {
    return "known"
}

01:30Creating the test file, awesomeLib_test.go, then creating the test. In this I also show some of the features of the Goland IDE that extracts and offers the function names of a module prefaced with Test and other naming that provides they perform a test, performance, or related testing functionality.

package awesomeLib

import "testing"

func TestGetKnownResult(t *testing.T) {
    got := GetKnownResult()
    if got != "known" {
        t.Error("Known result not received, test failed.")
    }
}

02:26Running the standard go test to execute the test. To run tests for all files within this module, such as if we’ve added multiple directories and other files, would be go test ./....

02:36Using Goland to run the tests with singular or multiple tests being executed. With Goland there are other capabilities to show test coverage, what percentage of functionality is covered by tests, and other various code metrics around testing, performance, and other telemetry.

That’s it, now the project is ready for elaboration and is setup for a TDD, BDD, or implement and test style approach to development.

For JavaScript, Go, Python, Terraform, and more infrastructure, web dev, and coding in general I stream regularly on Twitch at https://twitch.tv/adronhall, post the VOD’s to YouTube along with entirely new tech and metal content at https://youtube.com/c/ThrashingCode.

WebStorm JavaScripting & Noding Workflow Webinar Recording

Today the JetBrains team wrapping up final processing for my webinar from last week. You can check out the webinar via their JetBrains Youtube Channel:

JavaScriptFor even more information be sure to check out the questions and answers on the JetBrain WebStorm IDE blog entry. Some of the questions include:

  • Q: How to enable Node.js support in PhpStorm (PyCharm, IntelliJ IDEA, RubyMine)?
  • Q:How to enable autocompletion for Express, Mocha and other libraries?
  • Q: Is it possible to debug a Node.js application that runs remotely? Is it possible to debug when your node and the rest of the dependencies (database, etc.) are running in a VM environment like Vagrant?
  • Q: Does the debugger support cluster mode?

…and others all here.

Distributed Coding Prefunc: Installing QuickCheck for Great Testing

Erlang LogoA few weeks ago I kicked off this series of “Distributed Coding Prefunc: Up and Running with Erlang” and had wanted to keep up the momentum, but as life goes I had to tackle a few other things first. But now, it’s time to get back on track with some distributed computing. I intend to write tests with my samples, as I often do, I decided to take a stab at .

Before going forward, note that there is QuickCheck for Haskell and there is a QuickCheck for Erlang. Since the point of this “Distributed Coding Prefunc” is to get started coding with Erlang from zero, I’ll be talking about the Erlang version here. This version is created by John Hughes and Koen Claessen, starting the Quviq Company in 2006.

To download QuickCheck choose the version you intend to use, I’ve chosen the commercial license version from the download page.

At the command prompt, install QuickCheck by running Erlang and then run the install with these commands.

Launch Erlang:

[sourcecode language=”bash”]
$ erl
Erlang R15B01 (erts-5.9.1) [source] [smp:4:4] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.9.1 (abort with ^G)
1>
[/sourcecode]

Then execute the install:

[sourcecode language=”Erlang”]
1> eqc_install:install().
[/sourcecode]

If the execution of the install displays this error, you’ll need to use sudo.

[sourcecode language=”bash”]
Installing ["pulse-1.27.7","eqc-1.27.7","eqc_mcerlang-1.27.7"].
Failed to copy pulse-1.27.7–copy returned {error,eacces}??
** exception exit: {{error,eacces},"pulse-1.27.7"}
in function eqc_install:’-copy_quickcheck/3-lc$^0/1-0-‘/3 (../src/eqc_install.erl, line 63)
in call from eqc_install:install2/4 (../src/eqc_install.erl, line 44)
[/sourcecode]

Kill Erlang with a ctrl+c and restart Erlang with the sudo command.

[sourcecode language=”bash”]
$ sudo erl
[/sourcecode]

Now when you install you should see the following result or something similar. You’ll be asked to continue, select lowercase ‘y’ to continue. It may be different for some, but when I hit uppercase ‘Y’ (I suppose I got overzealous to install QuickCheck) it finished as if I’d hit no or something else.

[sourcecode language=”bash”]
1> eqc_install:install().
Installation program for "Quviq QuickCheck" version 1.27.7.
Installing in directory /usr/local/lib/erlang/lib.
This will delete conflicting versions of QuickCheck, namely
[]
Proceed? y
Installing ["pulse-1.27.7","eqc-1.27.7","eqc_mcerlang-1.27.7"].
Quviq QuickCheck is installed successfully.
Looking in "/Users/adronhall"… .emacs not found
Could not find your .emacs file!
Try install("path-to-emacs-file") or install(new_emacs).
Bookmark the documentation at /usr/local/lib/erlang/lib/eqc-1.27.7/doc/index.html.
ok
[/sourcecode]

You’ll note above, I don’t currently have emacs installed. The reason it looks for emacs is because QuickCheck has templates/ops mode for emacs. So if you use emacs you’re in luck. I on the other hand, don’t, so I’ll just be using this from wherever I’m using it.

In addition to the lack of emacs, another important thing to note from the message is the link to documentation. Once you get this link open it up and check out the docs. They’re broken out into easily readily topic spaces and are a good place to do initial reference checking while you’re writing up your specs.

If you have a license, it is important to note, that if you’ve used sudo with your installation you’ll need to kill your running Erlang session and start it anew without sudo. Otherwise you’ll run into issue down the road trying to use the libs (unless of course you want to go hack on your permissions manually). Once you’re ready to register the software it’s simply one command, where xxxxx is your license key.

[sourcecode language=”bash”]
eqc:registration("xxxxxxxxxxxx").
[/sourcecode]

Alright, next time we’re on to next steps…

Test Driven Development Built Name Generator Part 3

Part 1, Part 2.

Now it is time finally for the random name generation.  I’ve gotten everything into place, so it’s just a matter of grabbing the names and randomizing among them.  Just as a check, after Part 2 was finished I had a total of 98,572 rows of data, or simply 98,572 names.

Many times I would not write actual unit tests against the database as it breaks isolation.  This time though, I’m making an exception.  First I added a reference to Generator.Core, System.Data, and System.Data.Entity.  I then created a new unit test class called DatabaseTests and added the following test to get things rolling.  Keep in mind, since these tests break isolation, I don’t write them in the red light green light idea of TDD.  My assumption is that they only prove the database is setup, running, the connection string is correct, and other minor configuration based and server based components.  In addition, yes, these are somewhat silly tests, such as the RetrieveFirstName() test has a bit of redundancy to it, but the point is to have an automated test to assure that the data has been moved into the database and is returning appropriately.

[sourcecode language=”csharp”]
[TestClass]
public class DatabaseTests
{
[TestMethod]
public void RetrieveFirstFemaleName()
{
var entities = new GeneratorEntities();
var returnName = (from name in entities.Names
where name.Type == "Female First Names"
select name).FirstOrDefault();
Assert.IsNotNull(returnName);
Assert.IsTrue(returnName.Name != string.Empty);
}

[TestMethod]
public void RetrieveLastName()
{
var entities = new GeneratorEntities();
var returnName = (from name in entities.Names
where name.Type == "Last Names"
select name).FirstOrDefault();
Assert.IsNotNull(returnName);
Assert.IsTrue(returnName.Name != string.Empty);
}

[TestMethod]
public void RetrieveFirstMaleName()
{
var entities = new GeneratorEntities();
var returnName = (from name in entities.Names
where name.Type == "Male First Names"
select name).FirstOrDefault();
Assert.IsNotNull(returnName);
Assert.IsTrue(returnName.Name != string.Empty);
}

[TestMethod]
public void RetrieveFirstName()
{
var entities = new GeneratorEntities();
var returnName = (from name in entities.Names
where name.Type == "Female First Names" || name.Type == "Male First Names"
select name).FirstOrDefault();
Assert.IsNotNull(returnName);
Assert.IsTrue(returnName.Name != string.Empty && returnName.Type == "Female First Names" ||
returnName.Type == "Male First Names");
}
}
[/sourcecode]

The next step now was to refactor the existing tests to prove the assembly of the name data transfer objects that would hold the first name and last name derived from the returned entity objects.

The first thing I did was break out the actual name objects into their respective files.  I did this using ReSharper, because it’s super insanely simple with ReSharper.  After that I put the class files in the project that has the model.  Next I fixed the namespaces to Generator.Core.Model.  The class files after these changes looked like the code below.

IFullName.c

[sourcecode language=”csharp”]
namespace Generator.Core.Model
{
public interface IFullName
{
string FirstName { get; set; }
string LastName { get; set; }
}
}
[/sourcecode]

FullName.cs

[sourcecode language=”csharp”]
namespace Generator.Core.Model
{
public class FullName : IFullName
{
public FullName()
{
FirstName = string.Empty;
LastName = string.Empty;
}

#region IFullName Members

public string FirstName { get; set; }
public string LastName { get; set; }

#endregion
}
}
[/sourcecode]

NameFactory.cs

[sourcecode language=”csharp”]
namespace Generator.Core.Model
{
public class NameFactory
{
public static IFullName Build()
{
return new FullName {FirstName = "TestFirst", LastName = "TestLast"};
}
}
}
[/sourcecode]

Now that we have these files moved out to the project where all the munging will happen, I’m going to start the actual refactor of the tests.  What I’ve come up with for the test refactor is as follows.

[sourcecode language=”csharp”]
using Generator.Core.Model;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Factory.Tests
{
[TestClass]
public class FactoryNameBuilder
{
[TestMethod]
public void VerifyFullNameObjectInstantiatesWithNames()
{
var name = new FullName();
Assert.IsTrue(name.FirstName.Length == 0);
Assert.IsTrue(name.LastName.Length == 0);
}

[TestMethod]
public void VerifyFullNameObjectReturnsFromFactory()
{
var factory = new NameFactory();
IFullName name = factory.Build();
Assert.IsTrue(name.FirstName.Length > 0);
Assert.IsTrue(name.LastName.Length > 0);
}

[TestMethod]
public void VerifyFullNameIsRandom()
{
var factory = new NameFactory();
IFullName nameOne = factory.Build();
IFullName nameTwo = factory.Build();

Assert.AreNotEqual(nameOne.FirstName, nameTwo.FirstName);
Assert.AreNotEqual(nameOne.LastName, nameTwo.LastName);
}
}
}
[/sourcecode]

In the factory I removed the fake return and fleshed out the appropriate build method.

[sourcecode language=”csharp”]
using System;
using System.Collections.Generic;
using System.Linq;

namespace Generator.Core.Model
{
public class NameFactory
{
public IFullName Build()
{
Random rand = new Random(DateTime.Now.Millisecond);

GeneratorEntities entities = new GeneratorEntities();

List FirstNames = (from name in entities.Names
where name.Type == "Female First Names" || name.Type == "Male First Names"
select name).ToList();
List LastNames = (from name in entities.Names
where name.Type == "Last Names"
select name).ToList();

FullName fullName = new FullName();
fullName.FirstName = FirstNames[rand.Next(0, FirstNames.Count)].Name;
fullName.LastName = LastNames[rand.Next(0, LastNames.Count)].Name;

return fullName;
}
}
}
[/sourcecode]

Run the tests now and you have a random name gold mine.  However, I wanted a bit more than that.  With another test added…

[sourcecode language=”csharp”]
[TestMethod]
public void VerifyMultipleNameReturn()
{
var factory = new NameFactory();
List<IFullName> list = factory.Build(1000);

for (int i = 0; i < list.Count; i++)
{
int compareUp = i + 1;
if (compareUp == list.Count)
{
compareUp = 0;
}
Assert.AreNotEqual(list[compareUp].FirstName + list[compareUp].LastName, list[i].FirstName + list[i].LastName);
}
}
[/sourcecode]

…then the extra Build method.

[sourcecode language=”csharp”]
public List<IFullName> Build(int numberOfNames)
{
var rand = new Random(DateTime.Now.Millisecond);
var entities = new GeneratorEntities();

List<Names> FirstNames = (from name in entities.Names
where name.Type == "Female First Names" || name.Type == "Male First Names"
select name).ToList();
List<Names> LastNames = (from name in entities.Names
where name.Type == "Last Names"
select name).ToList();

var names = new List<IFullName>();

for (int i = 0; i < numberOfNames; i++)
{
var fullName = new FullName();
fullName.FirstName = FirstNames[rand.Next(0, FirstNames.Count)].Name;
fullName.LastName = LastNames[rand.Next(0, LastNames.Count)].Name;
names.Add(fullName);
}

return names;
}
[/sourcecode]

and now I have a strong verification that I get solid randoms for 1000 name pairs.  I bumped it up to 2000 too just for fun, and didn’t hit duplicates until I put it up to 200,000.

Test Driven Development Built Name Generator Part 2

Part 1Part 3.

Alright, time to tear into getting that name data imported into the database.  To review the previous entry check out part 1.

Next I set the Windows App Project I added in part 1 to be the startup project.  After that I created a screen that looks like the image below (click to see larger image).

Also add an open file dialog control.  Next double click on the Process button and add the following code.  Make sure not to miss the instantiation of the names list property in the initialization.

[sourcecode language=”csharp”]
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using System.Windows.Forms;

namespace TextFileImporter
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Names = new List();
}

private List Names { get; set; }

private void buttonProcessFile_Click(object sender, EventArgs e)
{
if (openFile.ShowDialog() == DialogResult.OK)
{
if (File.Exists(openFile.FileName))
{
TextReader tr = new StreamReader(openFile.FileName);
textProcessedFile.Text = tr.ReadToEnd();
tr.Close();
// Cleanup text.
textProcessedFile.Text = ProcessName(textProcessedFile.Text);
}
else
{
MessageBox.Show("Select a file that exists.", "File doesn’t exist.", MessageBoxButtons.OK,
MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
}
}
}

private string ProcessName(string textBody)
{
var regex = new Regex("[^A-Z’]+");
textBody = regex.Replace(textBody, " ");

foreach (var s in textBody.Split(Convert.ToChar(" ")))
{
Names.Add(s);
}

return textBody;
}
}
}
[/sourcecode]

With the beauty of those regular expressions the files will parse appropriately in about 1-5 seconds.  Next we need a way to write this data into the database.  I did this by adding a Class Project named Generator.Core and added a folder called Model.

In the Model Directory I added a new ADO.NET Entity Framework Model.  The images below show my steps through the wizard.

  • Wizard # 1 - Adding Data Model.Wizard # 1 – Adding Data Model.
  • Wizard # 2 - Adding Data Model.Wizard # 2 – Adding Data Model.
  • Wizard # 3 - Adding Data Model.Wizard # 3 – Adding Data Model.
  • Wizard # 4 - Adding Data Model.Wizard # 4 – Adding Data Model.
  • Wizard # 5 - Adding Data Model.Wizard # 5 – Adding Data Model.

.smugcontainer div {overflow: hidden;line-height: 1.1;margin-top: 10px;font-family: verdana, arial, lucida, sans-serif;font-size: 85%;background-color1: rgb(20, 20, 20);}
.smugimg li {float: left;display: block;width: 160px;height: 200px;background-position: 50% 50%;margin-right: 10px;margin-bottom: 10px;}
.smugimg li img {width: auto; height: auto; border: solid 1px #aaa; background: #555; padding: 2px; vertical-align: middle;}
.smugimg a {display: block;text-align: center;text-decoration: none; color1: rgb(240,240,240);}
.smugimg a:hover img {border: 3px solid #6da6d1; padding: 0px;}

.smugcontainer div {overflow: hidden;line-height: 1.1;margin-top: 10px;font-family: verdana, arial, lucida, sans-serif;font-size: 85%;background-color1: rgb(20, 20, 20);}
.smugimg li {float: left;display: block;width: 160px;height: 200px;background-position: 50% 50%;margin-right: 10px;margin-bottom: 10px;}
.smugimg li img {width: auto; height: auto; border: solid 1px #aaa; background: #555; padding: 2px; vertical-align: middle;}
.smugimg a {display: block;text-align: center;text-decoration: none; color1: rgb(240,240,240);}
.smugimg a:hover img {border: 3px solid #6da6d1; padding: 0px;}

At the end I also deleted the Class1.cs file from the project.

I then added a reference to the Generator.Core Project in the TextFileImporter Application Project.  Next add an application configuration file to the TextFileImporter Project with the following configuration section.

[sourcecode language=”xml”]
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<connectionStrings>
<add name="GeneratorEntities" connectionString="metadata=res://*/Model.Data.csdl|res://*/Model.Data.ssdl|res://*/Model.Data.msl;provider=System.Data.SqlClient;provider connection string=&quot;Data Source=.\carriage;Initial Catalog=Generator;Integrated Security=True;Pooling=False;MultipleActiveResultSets=True&quot;" providerName="System.Data.EntityClient" />
</connectionStrings>
</configuration>
[/sourcecode]

At the last minute, and to make sure anyone following along with these instructions is really paying attention, I made a minor change to the database table.  I changed the column Type to a data type of nvarchar(50).  I then updated the Data.edmx file in the Generator.Core Project.  To do this open up the file and right click anywhere in the white space around the model.  Then click on Update Model from Database….  Now, as things go, the stupid model didn’t update for me.  This is something that seems to occur very frequetly with the ADO.NET Entity Framework Model Files.  Since it didn’t update I had to manually right click on the Type Property and then set the Type of the Type (yes I know, redundant naming) to String.

So if anyone from Microsoft is reading this, the entity model files are STILL broken for some reason.  It’s been about 6 months since the entity framework and such where in beta and they still behave in many ways like they’re in beta, please fix this.  k thx bye.

Next I double clicked the Save (buttonSaveToDb) button and entered the following code to write the file data into the database.

[sourcecode language=”csharp”]
private void buttonSaveToDb_Click(object sender, EventArgs e)
{
if (comboNameType.Text == string.Empty)
{
MessageBox.Show("Select a type of name.", "Select Name", MessageBoxButtons.OK,
MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
}
else
{
// TODO Write to DB.
var generatorEntities = new GeneratorEntities();
foreach (var name in Names)
{
var newName =
new Names
{
NameId = Guid.NewGuid(),
Name = name,
Type = comboNameType.Text
};
generatorEntities.AddToNames(newName);
}
generatorEntities.SaveChanges(true);
}
}
[/sourcecode]

Then a quick reference and that finishes up the TextFileImporter Project.

[sourcecode language=”csharp”]
using Generator.Core.Model;
[/sourcecode]

Now mind you, I broke TDD principles because this app was merely a utility, would be used a few times, and above all breaks isolation and crosses boundaries.  A good rule is to not write tests for a project like this.  Unless you feel it absolutely necessary then I wouldn’t even think of it.

Now run the application and open and import each of the three files into the database.  This will give us the data we need for the next step of our random name generator.