using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace TestingIntoSingleton
{
[TestClass]
public class TestActiveUsers
{
[TestMethod]
public void Should_List_Logged_In_Users()
{
ActiveUsers UserManager = ActiveUsers.GetActiveUsers();
UserManager.Add("Brandon");
UserManager.Add("Amy");
UserManager.Add("Jack");
List<string> ExpectedUsers = new List<string>();
ExpectedUsers.Add("Brandon");
ExpectedUsers.Add("Amy");
ExpectedUsers.Add("Jack");
foreach (var ExpectedUser in ExpectedUsers)
{
Assert.IsTrue( UserManager.Users.Contains(ExpectedUser));
}
}
[TestMethod]
public void Should_Have_Only_One_Instance_Of_ActiveUsers()
{
ActiveUsers UserManager1 = ActiveUsers.GetActiveUsers();
ActiveUsers UserManager2 = ActiveUsers.GetActiveUsers();
UserManager1.Add("User");
Assert.IsTrue(UserManager2.Users.Contains("User"));
}
[TestMethod]
public void Should_Not_Allow_New_Instances()
{
try
{
ActiveUsers UserManager = new ActiveUsers();
//We should not get this far
Assert.Fail();
}
catch (System.Exception ex)
{
Assert.AreEqual("This object must be instantiated by the GetActiveUsers method", ex.Message);
}
}
}
public class ActiveUsers
{
private static ActiveUsers _instance;
public List<string> Users;
public ActiveUsers()
{
throw new System.Exception("This object must be instantiated by the GetActiveUsers method");
}
private ActiveUsers(bool YouAreASingleton)
{
Users = new List<string>();
}
public static ActiveUsers GetActiveUsers()
{
if (_instance == null)
{
_instance = new ActiveUsers(true);
}
return _instance;
}
public void Add(string User)
{
Users.Add(User);
}
}
}
Refactorings
No refactoring yet !
Brandon Joyce
February 10, 2009, February 10, 2009 04:25, permalink
I think this is better. Using reflection now on the third test to make sure that the constructor is private. This looks much cleaner.
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Reflection;
namespace TestingIntoSingleton
{
[TestClass]
public class TestActiveSessions
{
[TestMethod]
public void Should_List_Logged_In_Users()
{
ActiveUsers UserManager = ActiveUsers.GetActiveUsers();
UserManager.Add("Brandon");
UserManager.Add("Amy");
UserManager.Add("Jack");
List<string> ExpectedUsers = new List<string>();
ExpectedUsers.Add("Brandon");
ExpectedUsers.Add("Amy");
ExpectedUsers.Add("Jack");
foreach (var ExpectedUser in ExpectedUsers)
{
Assert.IsTrue( UserManager.Users.Contains(ExpectedUser));
}
}
[TestMethod]
public void Should_Have_Only_One_Instance_Of_ActiveUsers()
{
ActiveUsers UserManager1 = ActiveUsers.GetActiveUsers();
ActiveUsers UserManager2 = ActiveUsers.GetActiveUsers();
UserManager1.Add("User");
Assert.IsTrue(UserManager2.Users.Contains("User"));
}
[TestMethod]
public void Should_Not_Allow_New_Instances()
{
ConstructorInfo ci =
typeof(ActiveUsers).GetConstructor(
BindingFlags.Instance |
BindingFlags.NonPublic,
null,
System.Type.EmptyTypes,
null
);
Assert.IsNotNull(ci);
}
}
public class ActiveUsers
{
private static ActiveUsers _instance;
public List<string> Users;
private ActiveUsers()
{
Users = new List<string>();
}
public static ActiveUsers GetActiveUsers()
{
if (_instance == null)
{
_instance = new ActiveUsers();
}
return _instance;
}
public void Add(string User)
{
Users.Add(User);
}
}
}
Quiz
February 16, 2009, February 16, 2009 11:27, permalink
It's lazy evaluated too. ;)
public class ActiveUsers
{
private static readonly ActiveUsers _instance = new ActiveUsers();
public readonly List<string> Users = new List<string>();
public void Add(string User)
{
Users.Add(User);
}
}
Jonathan Starr
March 13, 2009, March 13, 2009 20:44, permalink
How about this test?
[TestMethod]
[ExpectedException(typeof(MissingMethodException))]
public void TestCannotBeConstructed()
{
object result = Activator.CreateInstance(typeof(ActiveUsers));
}
Brandon Joyce
March 14, 2009, March 14, 2009 00:48, permalink
Cool. That must be NUnit. It takes the same approach with exceptions as my original, but is much cleaner. Thanks!
I am doing a step by step example of TDD'ing towards the singleton pattern. The step by step Red, Green, Refactor cycle is at http://blog.sonerdy.com/2009/02/testing-into-singleton-pattern.html I am wondering if anyone has a more elegant way of testing that the object can only be instantiated by the factory method. This example uses an assertion that expects an exception when trying to new up the object the normal way. I haven't gone as far as to make sure this is thread safe. It's more of an excercise in Test-Driven development, and working towards a pattern. The idea of the ActiveUsers class is that it will have a list of the current users of the program. It's just a simple problem.