I have the following class
public interface IAuthProvider
{
string GenerateKey();
}
public class AuthProvider : IAuthProvider
{
public string GenerateKey()
{
using (var rng = new RNGCryptoServiceProvider())
{
var data = new byte[16];
rng.GetBytes(data);
return BitConverter.ToString(data).Replace("-","");
}
}
}
I also have the follow unit tests to go with it
[TestClass]
public class AuthProviderTests
{
private AuthProvider _provider;
private string _key;
[TestInitialize]
public void Initialize()
{
_provider = new AuthProvider();
_key = _provider.GenerateKey();
}
[TestMethod]
public void GenerateKey_key_length_is_32_characters()
{
Assert.AreEqual(32, _key.Length);
}
[TestMethod]
public void GenerateKey_key_is_valid_uppercase_hexidecimal_string()
{
Assert.IsTrue(_key.All(c =>
(c >= '0' && c <= '9') ||
(c >= 'A' && c <= 'F')
));
}
[TestMethod]
public void GenerateKey_keys_are_random()
{
var keys = new List<string>
{
_provider.GenerateKey(),
_provider.GenerateKey(),
_provider.GenerateKey(),
_provider.GenerateKey(),
_provider.GenerateKey()
};
var distinctCount = keys.Distinct().Count();
Assert.AreEqual(5, distinctCount);
}
}
Everything works great. However I need to create a method (and tests to go with it) called GenerateSecret. This method will do exactly the same as GenerateKey().
Now I am thinking I should create a method called GenerateRandomHexString(int bytes) and copy the code from GenerateKey into it. Then for GenerateKey and GenerateSecret I should use the follow code:
public interface IAuthProvider
{
string GenerateKey();
string GenerateSecret();
string GenerateRandomHexString(int bytes);
}
public class AuthProvider : IAuthProvider
{
public string GenerateKey()
{
return GenerateRandomHexString(16);
}
public string GenerateSecret()
{
return GenerateRandomHexString(16);
}
public string GenerateRandomHexString(int bytes)
{
using (var rng = new RNGCryptoServiceProvider())
{
var data = new byte[bytes];
rng.GetBytes(data);
return BitConverter.ToString(data).Replace("-","");
}
}
}
Now for the tests, should I just write the tests for the GenerateRandomHexString method, or should I write tests also for the GenerateSecret and GenerateKey (which will be pretty much identical tests)
Why do need two methods that do the same thing?
Regardless, you should write separate tests.
generally unit tests should cover the public interface and not non-public members and your GenerateHexString probably shouldn't be public if it is only to be used by the other methods
your implementations are the same now, but they may diverge in the future. Without distinct test cases you may miss breaking changes introduced by someone changing one of those implementations
ultimately your tests shouldn't know or care about the internal implementation details of your code
One thing that might help in nUnit would be the TestCaseSource attribute. It would allow you to define the same test cases for both methods saving some duplication in your code.
It's a bad idea to create many interface methods to do the same thing. I also don't put overloads on interfaces. The problem this creates is that methods that have the same semantic meaning can have wildly divergent implementations. They might not in the simplest cases, but simple cases often become complex ones eventually.
I love extension methods for this problem.
public interface IAuthProvider
{
string GenerateKey();
}
public static class IAuthProviderExtensions
{
public static string GenerateSecret(this IAuthProvider provider)
{
return provider.GenerateKey();
}
}
Test:
[Test]
public void GenerateSecretIsAliasForGenerateKey()
{
var mockProvider = new Mock<IAuthProvider>();
var key = GenerateARandomStringSomehow();
mockProvider.Setup(p=>p.GenerateKey()).Returns(key);
Assert.That(mockProvider.Object.GenerateSecret(), Is.EqualTo(key));
}
Related
we have a method which takes the folder name and number of days as a parameter.
public void Delete(string folder, int days)
{
var files = Directory.GetFiles(folder);
foreach (var file in files)
{
var fi = new FileInfo(file);
var fiCreationTime = fi.CreationTime;
var deleteOlderThan= DateTime.Now.AddDays(-days);
if (fiCreationTime >= deleteOlderThan) continue;
fi.Delete();
}
}
What is the best way to unit test such methods in c#
Actually you cannot unit test your method, because it depends on external APIs (FileSystem, DateTime).
So what you should do is separate logic and integration with external sources, it might look like this:
public class MyFileInfo
{
public string FileName { get; set; }
public DateTime CreationTime { get; set; }
}
public interface IDateTimeProvider
{
DateTime GetCurrentTime();
}
public interface IMyFileSystemService
{
IEnumerable<MyFileInfo> GetFileInfos(string folder);
void DeleteFile(MyFileInfo myFileInfo);
}
public class MyService
{
private readonly IMyFileSystemService _myFileSystemService;
private readonly IDateTimeProvider _dateTimeProvider;
public MyService(IMyFileSystemService myFileSystemService, IDateTimeProvider dateTimeProvider)
{
_myFileSystemService = myFileSystemService;
_dateTimeProvider = dateTimeProvider;
}
public void Delete(string folder, int days)
{
var files = _myFileSystemService.GetFileInfos(folder);
foreach (var file in files)
{
var deleteOlderThan = _dateTimeProvider.GetCurrentTime().AddDays(-days);
if (file.CreationTime >= deleteOlderThan) continue;
_myFileSystemService.DeleteFile(file);
}
}
}
I think implementation of interfaces IDateTimeProvider and IMyFileSystemService should not be an issue.
Now you can write clean unit tests for MyService.Delete
If you want to unit test the method you have shown it would be difficult in the way it is currently written, but we could mock the File class and pass an interface for it to use:
public class FileDeleter
{
private readonly IFileOperator _fileOperator;
public FileDeleter(IFileOperator fileOperator)
{
_fileOperator= fileOperator
}
public void Delete(string folder, int days)
{
var files = _fileClass.GetFiles(folder);
foreach (var file in files)
{
var fi = _fileClass.GetFileInfo(file);
var fiCreationTime = fi.CreationTime;
var deleteOlderThan= DateTime.Now.AddDays(-days);
if (fiCreationTime >= deleteOlderThan)
continue;
fi.Delete();
}
}
}
public interface IFileClass
{
IEnumerable<string> GetFiles(string path);
IFileInfo GetFileInfo(string filePath);
}
public interface IFileInfo
{
DateTime CreationTime { get; }
void Delete();
}
After that, simply mock the two classes with a library like: https://github.com/Moq/moq4/wiki/Quickstart
and write your unit tests testing whatever logic is required.
EDIT: As others have pointed out, datetime.now might be a good thing to mock too, but can be done in that same way.
Another possibility is to use static helper classes
public static class FileEx
{
public static Func<string, IEnumerable<string>> EnumerateFiles { set; get; }
= Directory.EnumerateFiles;
}
and then only use the helper classes:
var files = FileEx.EnumerateFiles(...);
This way you can change the method in your unit tests.
[Test]
public void Test()
{
FileEx.EnumerateFiles = (_) => new [] { "file1", "file2" };
// your test here
// Reset the method:
FileEx.EnumerateFiles = Directory.EnumerateFiles;
}
This works for most static helper methods and is way easier refactoring every class so it can be injected.
Downsides
you will lose function overloading.
will only work for static classes (in your example it won't work for FileInfo).
Upsides
really easy
easy to implement
easy to change while testing
easy to use
Update to remarks in the comments:
It is viable to replace system methods as Directory.EnumerateFiles in your unit tests.
Because you are testing your Delete method and one can assume that Microsoft has tested the framework code. Therefore the only thing the unit test must prove is that the Delete method has to correct output and side effects.
The 100% solution is that lot of this has to be injected in because it either has sideeffects or is non-determenistic:
1) Directory.GetFiles
2) new FileInfo(file)
3) fi.CreationTime
4) DateTime.Now.AddDays
5) fi.Delete
So you inject e.g. a datetimeservice in that in production that returns datetime, and in test where it always returns some fixed date. And use a mocking framework to check that sometimes the delete method is called, and other times it isn't called.
The perfect solution for your code would create an interface which has methods for all files operation and then mock those methods
but you can also create virtual methods for those file operation in your sample class and mock that method in a unit test
Following is code implementation of your actual code
public class Sample
{
public void Delete(string folder, int days)
{
var files = GetFiles(folder);
foreach (var file in files)
{
var fi = GetFileInfo(file);
var fiCreationTime = fi.CreationTime;
var deleteOlderThan = DateTime.Now.AddDays(-days);
if (fiCreationTime >= deleteOlderThan) continue;
DeleteFile(fi);
}
}
public virtual void DeleteFile(FileInfo f)
{
f.Delete();
}
public virtual string[] GetFiles(string path)
{
return Directory.GetFiles(path);
}
public virtual FileInfo GetFileInfo(string file)
{
return new FileInfo(file);
}
}
And following is your unit test class
public class NUnitTest
{
[TestFixture]
public class UnitTest1
{
private Mock<Sample> _sample;
private FileInfo _fileInfo;
[SetUp]
public void Setup()
{
_sample = new Mock<Sample>();
}
[Test]
public void File_Should_Not_Delete()
{
_fileInfo = new FileInfo("file");
_fileInfo.Create();
_sample.Setup(x => x.GetFiles(It.IsAny<string>())).Returns(() => new[] {"file1"});
_sample.Setup(x => x.GetFileInfo(It.IsAny<string>())).Returns(() => _fileInfo);
_sample.Setup(x => x.DeleteFile(It.IsAny<FileInfo>())).Verifiable();
_sample.Object.Delete("file1",2);
_sample.Verify(x => x.DeleteFile(It.IsAny<FileInfo>()), Times.Never);
}
[Test]
public void File_Should_Delete()
{
_fileInfo = new FileInfo("file1");
_fileInfo.Create();
_sample.Setup(x => x.GetFiles(It.IsAny<string>())).Returns(() => new[] { "file1" });
_sample.Setup(x => x.GetFileInfo(It.IsAny<string>())).Returns(() => _fileInfo);
_sample.Setup(x => x.DeleteFile(It.IsAny<FileInfo>())).Verifiable();
_sample.Object.Delete("file1", -2);
_sample.Verify(x => x.DeleteFile(It.IsAny<FileInfo>()), Times.Once);
}
}
}
I know this is not good design practice but I just want to showcase you a different way of doing unit testing using a virtual method.
Bestway is to create an interface and mock those interface method which I created as a virtual
My unit testing method is as follows
[Test]
public void TrackPublicationChangesOnCDSTest()
{
//Arrange
// objDiskDeliveryBO = new DiskDeliveryBO();
//Act
var actualResult = objDiskDeliveryBO.TrackPublicationChangesOnCDS();
//Assert
var expectedZipName = 0;
Assert.AreEqual(expectedZipName, actualResult);
}
The Actual method TrackPublicationChangesOnCDS in BO is as follows
public int TrackPublicationChangesOnCDS()
{
var resultFlag = -1;
try
{
string pubUpdateFileCDSPath = CommonCalls.PubUpdateFileCDSPath;
string pubUpdateFileLocalPath = CommonCalls.PubUpdateFileLocalPath;
if (File.Exists(pubUpdateFileCDSPath))
File.Copy(pubUpdateFileCDSPath, pubUpdateFileLocalPath, true);
if (File.Exists(pubUpdateFileLocalPath))
{
string[] pubRecords = File.ReadAllLines(pubUpdateFileLocalPath);
var pubRecordsExceptToday = pubRecords.Where(p => !p.Trim().EndsWith(DateTime.Now.ToString("dd/MM/yy"))).ToList();
resultFlag = new DiskDeliveryDAO().TrackPublicationChangesOnCDS(pubRecordsExceptToday);
File.WriteAllText(pubUpdateFileLocalPath, string.Empty);
string[] pubRecordsCDS = File.ReadAllLines(pubUpdateFileCDSPath);
var pubRecordsTodayCDS = pubRecordsCDS.Where(p => p.Trim().EndsWith(DateTime.Now.ToString("dd/MM/yy"))).ToList();
File.WriteAllLines(pubUpdateFileCDSPath, pubRecordsTodayCDS);
}
return resultFlag;
}
catch (Exception)
{
return -1;
}
}
While debugging Debugger comes till
string pubUpdateFileCDSPath = CommonCalls.PubUpdateFileCDSPath;
But CommonCalls.PubUpdateFileCDSPath; return empty string . It should return a file path . when the method is called directly it works fine . It doesn't work when it is called inside a unit testing method.
CommonCalls.PubUpdateFileCDSPath is a static property defined as below .
public static string PubUpdateFileCDSPath
{
get { return GetXmlConfigValue("PubUpdateFileCDSPath"); }
}
public static string GetXmlConfigValue(string nodeName)
{
var xml = new XmlDocument();
xml.Load(ConfigValuesXml);
var node = xml.SelectSingleNode("JanesOfflineDeliveryService/" + nodeName);
return node != null ? node.InnerText : string.Empty;
}
Configvaluesxml is a xml file path . Contents of the file is
<JanesOfflineDeliveryService>
<PubUpdateFileCDSPath>D:\OfflineDelivery\CDS\pub_update.txt</PubUpdateFileCDSPath>
<PubUpdateFileLocalPath>D:\pub_update.txt</PubUpdateFileLocalPath>
</JanesOfflineDeliveryService>
In your test scenario GetXmlConfigValue("PubUpdateFileCDSPath") does not exist, so string empty is returned. Thats why you should avoid static methods, because they are not mockable. A workaround could be to pass the path variables into the method.
Using static dependencies make unit testing code in isolation difficult. invert the dependency by abstracting and injecting them into the dependent class.
public interface ICommonCalls {
string PubUpdateFileCDSPath { get; }
string PubUpdateFileLocalPath { get; }
}
the implementation of the above interface would either wrap the your static calls or better yet just implement them.
The dependent class would be refactored to allow for the dependency inversion.
public class DiskDeliveryBO {
private readonly ICommonCalls CommonCalls;
public DiskDeliveryBO(ICommonCalls common) {
this.CommonCalls = common;
}
//...other code removed for brevity.
}
However the target method also has a lot of tight coupling to implementation concerns like the file system. That too should be abstracted and inverted out of the dependent class.
I have the followed function and trying to add Unit Test on a old project. I'm a beginner in Unit Test so forgive me if the question is stupid ...
public static string GetDefaultName(bool isResponsive)
{
//Read web.config file
Configuration configuration = WebConfigurationManager.OpenWebConfiguration(System.Web.HttpContext.Current.Request.ApplicationPath);
if (!isResponsive)
{
if (configuration.AppSettings.Settings.AllKeys.Contains("defaultTheme"))
{
return configuration.AppSettings.Settings["defaultTheme"].Value;
}
else
return "default";
}
else
{
// ...
}
}
And I'm trying to write an Unit Test in this way :
[TestMethod]
public void ReturnDefaulThemeNametIfThemeIsResponsive()
{
var theme = new Theme {isResponsive = true};
var defaultName = Themes.GetDefaultName(theme.isResponsive);
Assert.AreEqual(defaultName, "defaultThemeResponsive");
}
I wonder what is the best way to test this static function, and how to mock the part who read the web.config file ?
I try to stay away from static utilities that have dependencies as they are difficult to unit test. But in this case it is possible. You will have to do some refactoring.
First you need to abstract all calls to access configuration.
public interface IThemeSettings {
bool Contains(string key);
string this[string key] { get; }
}
You can then update the static Themes utility class to use this abstraction as a dependency
public static class Themes {
private static IThemeSettings themes;
public static void Configure(Func<IThemeSettings> factory) {
if (factory == null) throw new InvalidOperationException("Must provide a valid factory method");
themes = factory();
}
public static string GetDefaultName(bool isResponsive) {
if (themes == null) throw new InvalidOperationException("Themes has not been configured.");
string result = string.Empty;
if (!isResponsive) {
if (themes.Contains("defaultTheme")) {
result = themes["defaultTheme"];
} else
result = "default";
} else {
// ...
}
return result;
}
//...
}
That wat you can now configure the utility to use mocks when testing
[TestMethod]
public void ReturnDefaulThemeNametIfThemeIsResponsive() {
//Arrange
var key = "defaultTheme";
var expected = "defaultThemeResponsive";
var mockSettings = new Mock<IThemeSettings>();
mockSettings.Setup(m => m.Contains(key)).Returns(true);
mockSettings.Setup(m => m[key]).Returns(expected);
//In production you would also do something like this with
//the actual production implementation, not a mock
Themes.Configure(() => mockSettings.Object);
var theme = new Theme { isResponsive = true };
//Act
var defaultName = Themes.GetDefaultName(theme.isResponsive);
//Assert
Assert.AreEqual(expected, defaultName);
}
In this case I used Moq as the mocking framework.
Some advice. Try not to have your classes tightly coupled to HttpContext. Your classes should depend on abstractions and not on concretions.
The way your method is designed at the moment does not allow you to mock the part that reads the config file. If you want to be able to do that you need to make it a parameter to your method. One way to make that easier is to define an interface like
public interface ISetting
{
string GetConfigItem(string itemName);
}
Then wrap the Configuration object in a settings manager class that implements this.
public class MySettings:ISetting
{
public string GetConfigItem(string ItemName)
{
// return value of the setting. In your case code that gets value of "defaultTheme"
}
}
Your method will now have a dependency on ISetting.
For testing purposes you can create a mock that implements the interface and will return what ever value you want independent of the current state and content of the web.config
public class SettingsTestHelper:ISetting
{
private _valueToReturn;
public SettingsTestHelper(string valueToReturn)
{
_valueToReturn=valueToReturn;
}
public string GetConfigItem(string itemName)
{
return valueToReturn;
}
}
With this you can now create a unit test(doesn't compile, but you'll get the idea)
[TestMethod]
public void CanGetSetting()
{
var helper = new SettingsTestHelper("default");
var result = ClasThatImplementsYourStaticMethod.GetDefaultName(helper, true);
Assert.AreEqual(expected, actual);
}
I've recently had a real world use for the Strategy pattern. I find myself with hammer/nail syndrome where this pattern is my hammer and everything else is a nail. For kicks, I decided to try implementing FizzBuzz via the strategy pattern. Now, I know this is complete over kill. I've seen various Enterprise implementations of it, but this is my own implementation.
To my surprise and delight, this exercise turned up an interesting question: is there a standard or another pattern that works in conjunction with strategies to help you select which one to use? In my FizzBuzzStrategySelector class below, I put this logic in the Format function.
Obviously this implementation is not practical...but it might be if these Format methods actually had some real world logic to break down.
My basic question here is this: am I using the Strategy pattern correctly here?
class Program
{
static void Main(string[] args)
{
FizzBuzzStrategySelector fizzBuzzFormatter = new FizzBuzzStrategySelector();
for (int i = 1; i < 100; i++)
{
fizzBuzzFormatter.Format(i);
}
Console.ReadLine();
}
}
public interface IOutputFormatter
{
string FormatOutput(int value);
}
public class FizzBuzzStrategySelector
{
public IOutputFormatter formatStrategy;
public FizzBuzzStrategySelector() : this(new GeneralFormatter()) { }
public FizzBuzzStrategySelector(IOutputFormatter fizzBuzzFormatStrategy)
{
this.formatStrategy = fizzBuzzFormatStrategy;
}
public void Format(int value)
{
//THIS SEEMS LIKE A CODE SMELL. NOT SURE HOW TO WORK
//AROUND IT.
if(value % 15 == 0)
this.formatStrategy = new FizzBuzzFormatter();
else if(value % 3 == 0 )
this.formatStrategy = new FizzFormatter();
else if(value % 5 == 0)
this.formatStrategy = new BuzzFormatter();
else
this.formatStrategy = new GeneralFormatter();
Console.WriteLine(this.formatStrategy.FormatOutput(value));
}
}
public class GeneralFormatter : IOutputFormatter
{
public string FormatOutput(int value)
{
return value.ToString();
}
}
public class FizzBuzzFormatter : IOutputFormatter
{
public string FormatOutput(int value)
{
return "FizzBuzz";
}
}
public class BuzzFormatter : IOutputFormatter
{
public string FormatOutput(int value)
{
return "Buzz";
}
}
public class FizzFormatter : IOutputFormatter
{
public string FormatOutput(int value)
{
return "Fizz";;
}
}
Since (as you are aware) the Strategy Pattern is overkill for this problem, it is hard to say what would be "good" or "bad" design. However, my gut reaction would be to move the strategy selection logic into the strategies themselves, like so:
class FizzBuzzFormatter : IOutputFormatter
{
public bool Handles(int value) { return value.IsDivisibleBy(15); }
public string Handle(int value) { return "FizzBuzz"; }
}
This might be a little better in terms of composability, but you still need to make sure you have a list of IOutputFormatters in the correct order. With a problem this small, you can get away with anything. With a larger problem, you need to think about it and decide for yourself.
the different output formatters are part of the strategy pattern. typically there would be an object which requires the formatter. then you can call the formatter.
class Foo
{
public IOutputFormatter Formatter {get;set;}
}
var foo = new Foo();
foo.Formatter = new GeneralFormatter();
Console.WriteLine(foo.formatter.FormatValue("one");
foo.Formatter = new FizzBuzzFormatter();
Console.WriteLine(foo.formatter.FormatValue("one");
How the formatter is set, or which formatter is set can be the responsibility of another object.
public interface IServiceInvoker
{
R InvokeService<T, R>(Func<T, R> invokeHandler) where T : class;
}
public class MediaController : Controller
{
private IServiceInvoker _serviceInvoker;
public MediaController(IServiceInvoker serviceInvoker)
{
_serviceInvoker = serviceInvoker;
}
public JsonResult GetAllMedia()
{
var media = _serviceInvoker.InvokeService<IMediaService, List<MediaBase>>(proxy => proxy.GetAllMediaInJson());
JsonResult jsonResult = new JsonResult();
jsonResult.Data = media;
jsonResult.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
return jsonResult;
}
[TestClass]
public class MediaControllerTests
{
[TestMethod]
public void GetAllMedia()
{
JsonResult data;
var serviceInvoker = MockRepository.GenerateStub<IServiceInvoker>();
var media = CreateSeveralMedia();
serviceInvoker.Stub(c => c.InvokeService<IMediaService, List<MediaBase>>(p => p.GetAllMediaInJson())).Return(media);
data = new MediaController(serviceInvoker).GetAllMedia();
serviceInvoker.VerifyAllExpectations();
Assert.IsNotNull(data);
}
}
I am stubbing the service and returning a collection. When I run this test, media is null. Any idea, how can I set expectations on this mock ?
Just found a solution. It seems to be a little ugly, but it is the first iteration only probably more elegant version will appear soon. The idea is to create another stub and match Func<> against it:
I will provide code for my use case:
[Theory]
[InlineData(342, 31129, 3456)]
public void should_call_service_invoker_and_return_result(int number1, int number2, int expected)
{
var calculator = MockRepository.GenerateStub<ICalculator>();
calculator.Stub(_ => _.Add(number1, number2)).Return(expected);
var serviceInvoker = MockRepository.GenerateStub<ServiceInvoker<ICalculator>>();
serviceInvoker
.Stub(_ => _.Invoke(Arg<Func<ICalculator, int>>.Matches(d => d(calculator) == calculator.Add(number1, number2))))
.Return(expected);
var serviceConsumer = new ServiceConsumer(serviceInvoker);
var actual = serviceConsumer.GetAddResultFor(number1, number2);
Assert.Equal(expected, actual);
}
xUnit + extensions is used as testing framework. Please ignore Theory and InlineData stuff -- it is just another way to get rid of unnecessary test setup.
Here is the code of SUT:
public class ServiceConsumer
{
private readonly ServiceInvoker<ICalculator> serviceInvoker;
public ServiceConsumer(ServiceInvoker<ICalculator> serviceInvoker)
{
this.serviceInvoker = serviceInvoker;
}
public int GetAddResultFor(int number1, int number2)
{
return serviceInvoker.Invoke(_ => _.Add(number1, number2));
}
}
public class ServiceInvoker<T>
{
public virtual R Invoke<R>(Func<T, R> func)
{
throw new NotImplementedException();
}
}
public interface ICalculator
{
int Add(int number1, int number2);
}
Hope this will be helpful. Any suggestions of how to add more beauty are welcome :)
The lambda in your unit test compiles into a class-level method (a method inside your unit test). Inside your controller, a different lambda compiles into a class-level method (inside the controller). The stub set up in your unit test doesn't match the stub being executed in your controller, so Rhino Mocks returns a default (null). More here: http://groups.google.com/group/rhinomocks/browse_frm/thread/a33b165c16fc48ee?tvc=1