Introducing Nuget’s first TestAPI Package

Intro

Whenever I start new projects for clients, I find myself constructing a new test API from scratch. A test API is a utility or library that provides common test scenario dependencies for automated tests. I was never conscious of the repetitive task of implementing a new test API until I attempted to implement the UserLogin feature in reference to the Feature-Driven Architecture article that I wrote.

After constructing my solution explorer, I decided to perform TDD on the business logic required for user-login. I immediately began to construct a test API so that I could provide general values for test-input. For example, I created a constant called “SOME_ID” that you guessed it, had some arbitrary integer assigned to it. I then created another constant called “SOME_PASSWORD” that returned some arbitrary text to denote a password. After adding several constants to this API, I finally recognized value in making this library available on Nuget for others to use when performing TDD. As a result, I’m proud to announce that Bizmonger.TestAPI is now available on Nuget.

The following is the implementation for user authentication using this library.

Test Class:

using Login.UI;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using TestAPI;

namespace Login.Tests
{
    [TestClass]
    public class _Login
    {
        [TestMethod]
        public void valid_user_is_authenticated()
        {
            // Setup
            var login = new Commands().Login;
            var viewModel = new ViewModel();

            // Test
            var args = new object[3] { Gimme.SOME_ID,
                                       Gimme.SOME_PASSWORD,
                                       Gimme.SOME_AUTHENTICATOR_THAT_PASSES };
            login.Execute(args);

            // Verify
            Assert.IsTrue(viewModel.IsAuthenticated);
        }

        [TestMethod]
        public void invalid_user_is_not_authenticated()
        {
            // Setup
            var login = new Commands().Login;
            var viewModel = new ViewModel();

            // Test
            var args = new object[3] { Gimme.SOME_ID,
                                       Gimme.SOME_PASSWORD,
                                       Gimme.SOME_AUTHENTICATOR_THAT_FAILS };
            login.Execute(args);

            // Verify
            Assert.IsTrue(!viewModel.IsAuthenticated);
        }
    }
}

The “Gimme” class
In my test API, I created a class called Gimme. The sole purpose of this class is to provide arbitrary values for business logic dependencies. Such dependencies could be a numeric value, a text value, or really long text.

Example:

. . . 

var args = new object[3] { Gimme.SOME_ID,
                           Gimme.SOME_PASSWORD,
                           Gimme.SOME_AUTHENTICATOR_THAT_PASSES };
login.Execute(args);

Now, I’m on the fence when it comes to which syntax to use. The above code is more expressive. Hence, we used the prefix “Gimme”. However, we can also remove that prefix by referencing the Gimme class in our test class namespace.

Usage Example:

using Login.UI;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using static TestAPI.Gimme;

. . .

var args = new object[3] { SOME_ID,
                           SOME_PASSWORD,
                           SOME_AUTHENTICATOR_THAT_PASSES };

login.Execute(args);

Gimme Definition:

using TestAPI.Authenticators;

namespace TestAPI
{
    public partial class Gimme
    {
        public const int SOME_ID = 123456;
        public const int SOME_OTHER_ID = 456789;

        public const string SOME_EMAIL_ADDRESS = "ABC@BIZMONGER.COM";
        public const string SOME_OTHER_EMAIL_ADDRESS = "XYZ@BIZMONGER.NET";

        public const string SOME_PHONE_NUMBER = "2162914078";
        public const string SOME_OTHER_PHONE_NUMBER = "2169322921";

        public const string SOME_PASSWORD = "some_pasword";
        public const string SOME_OTHER_PASSWORD = "some_other_pasword";

        public const string SOME_SHORT_TEXT = "some_text";
        public const string SOME_OTHER_SHORT_TEXT = "some_alternative_text";

        public string SOME_LONG_TEXT = new string('X', 5000);
        public string SOME_OTHER_LONG_TEXT = new string('Y', 5000);

        public const int SOME_INTEGER_VALUE = 123;
        public const int SOME_OTHER_INTEGER_VALUE = 456;

        public const long SOME_LONG_NUMERIC_VALUE = 1234567890123456789;
        public const long SOME_OTHER_LONG_NUMERIC_VALUE = 9876543212345678;

        public const decimal SOME_DECIMAL_VALUE = 123.12345M;
        public const decimal SOME_OTHER_DECIMAL_VALUE = 456.45678M;

        public const decimal SOME_CURRENCY_VALUE = 99.99M;
        public const decimal SOME_OTHER_CURRENCY_VALUE = 49.99M;

        public static SuccessAuthenticator SOME_AUTHENTICATOR_THAT_PASSES = new SuccessAuthenticator();
        public static FailedAuthenticator SOME_AUTHENTICATOR_THAT_FAILS = new FailedAuthenticator();
    }
}

If you’re dying to see the System under Test (SUT) implementation then look below.

Commands Definition:

using Bizmonger.Patterns;
using System.Windows.Input;
using Login.Core;

namespace Login.UI
{
    public class Commands
    {
        public Commands()
        {
            Login = new DelegateCommand(OnLogin);
        }

        private void OnLogin(object obj)
        {
            var args = obj as object[];
            var userId = args[0] as string;
            var password = args[1] as string;
            var authenticator = args[2] as IAuthenticator;

            MessageBus.Instance.Publish("IsAuthenticated", authenticator.Authenticate());
        }

        public ICommand Login { get; private set; }
    }
}

ViewModel Definition:

using Bizmonger.Patterns;

namespace Login.UI
{
    public class ViewModel
    {
        public ViewModel()
        {
            MessageBus.Instance.Subscribe("IsAuthenticated", obj => IsAuthenticated = (bool)obj);
        }

        public bool IsAuthenticated { get; private set; }
    }
}

Conclusion

In conclusion, when I started new projects for clients, I found myself constructing a new test API from scratch each time. I was never conscious of this repetitive task until I reviewed my post on Feature-Driven Architecture. I then realized that I could publish a tool that can not only benefit me, but also benefit my community from performing the same mundane tasks when practicing TDD by leveraging a common TestAPI. As a result, developers can now pull down Bizmonger.TestAPI on Nuget to support their TDD.

NOTE:

Scott Nimrod is fascinated with Software Craftsmanship.

He loves responding to feedback and encourages people to share his articles.

He can be reached at scott.nimrod @ bizmonger.net

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: