I understand that you can unit test a void method by checking for its effects. However, looking at the loadConfigFile method in this code:
internal XmlDocument configData;
public ConfigFile()
{
configData = new XmlDocument();
}
/// <summary>
/// Load config file into memory
/// </summary>
/// <param name="filename">path and filename of config file</param>
public void loadConfigFile(string filename)
{
if(string.IsNullOrEmpty(filename))
throw new System.ArgumentException("You must specify a filename");
try
{
configData.Load(filename);
}
catch(Exception ex)
{
throw new Exception("Config file could not be loaded",ex);
}
}
It loads a config file into a private field - which needs to be kept private so that developers do not modify the value directly. Instead the modification will be done through setConfigValue and getConfigValue methods (which I would assume need to be tested separately).
Given this, how would I test that the loadConfigFile actually worked? As I cant access the private configData field.
Where else in that class is configData used?
If, say, you have a method like
public string GetValue()
{
return configData.GetsomeDataFromThis;
}
Then I suggest you have a test like so:
public void ReadValueFromLoadedConfigData()
{
// Arrange.
const string ExpectedValue = "Whatever";
var sut = new ConfigFile();
sut.loadConfigFile(#"C:\PathToTheConfigFile");
// Act.
string actual = sut.GetConfigValue();
// Assert.
Assert.AreEqual(ExpectedValue, actual);
}
In your tests, try to test only the public interactions, since going deep into the class, by having to read values of private fields, means your class isn't test friendly.
You could test that getConfigValue returned the values loaded from the file, basically.
Just because you test setConfigValue/getConfigValue in other tests doesn't mean that you can't use them in the test for loadConfigFile.
As an aside, I'd strongly urge you to follow .NET naming conventions, starting your method names with capital letters. (I'd also urge you to make your field private rather than internal...)
A unit test is basically a way to say "given this input, verify that this happened", it is not a substitute for verifying that your application is in a valid state.
In the example, the loadConfigFile method throws an exception if the precondition is not met, or the load operation failed. This will then be detected in the unit test, which will fail.
If any other validation is needed on the config beyond that no exception is thrown, that should be handled in the class itself.
Related
I'm reading a book on unit testing, below is the code example:
public class User {
private string _name;
public string Name {
get => _name;
set => _name = NormalizeName(value);
}
private string NormalizeName(string name) {
/* Trim name down to 50 characters */
}
}
public class UserController {
public void RenameUser(int userId, string newName) {
User user = GetUserFromDatabase(userId);
user.Name = newName;
SaveUserToDatabase(user);
}
}
The author says
UserController in this example is an application service. Assuming that the external client doesn't have a specific goal of normalizing user names, and all names are normalized solely due to restrictions from the application itself, the NormalizeName method in the User class can't be traced to the client's needs. Therefore, it's an implementation detail and should be made private. Moreover, tests shouldn't check this method directly. They should verify it only as part of the class's observable behavior-the Name property's setter in this example.
So the author means we shouldn't write a test to test NormalizeName method, instead, we should write a test to test Name property. But image if the developer didn't write NormalizeName method properly and names more than 50 characters are allowed to be input, which will cause an exception thrown later, shouldn't we write a NormalizeName method test to guard this?
The author is saying that you should test for this scenario by designing an appropriate test , indirectly, through the public User.name property, not with a test that directly calls NormalizeName.
Of course, it is important to test NormalizeName. But you can test it indirectly by testing the property. See this test:
[TestMethod]
public void NameProperty_TrimsLongNames()
{
// arrange
User user = new User();
string name = "very very very long name... and even longer... and still longer";
string expectedName = "very very very long name... and even longer... an";
// act
user.Name = name;
// assert
Assert.AreEqual(user.Name, expectedName);
}
By calling the setter, you also call NormalizeName. If this method doesn't work correctly, this test will fail. The fact that the functionality to trim the name is in this method, is an implementation detail. It might also be directly in the setter of the property. Hence you only call the setter in the test, because that is your observable behaviour: If I set the Name property to a new value, long names should be truncated. It is not important, if this is done via a private method, an extension method for the string class or somehow else.
I'm unit testing my C# application that Parses a CSV. I'm at 94% code coverage, because I can't force it to fail the try/catch blocks... I'm using CsvHelper from Nuget http://joshclose.github.io/CsvHelper
public void ParseCsv([FromBody] string csvText)
{
var parseCsv = new XsvData(new[] { "\t", "," });
try
{
using (var reader = new XsvReader(new StringReader(csvText)))
{
parseCsv.Read(reader, headerExists: true);
}
}
catch (Exception)
{
var response = new HttpResponseMessage(HttpStatusCode.BadRequest)
{
Content = new StringContent("Unable to read CSV."),
ReasonPhrase = "Invalid CSV"
};
throw new HttpResponseException(response);
}
}
I've tried passing the most obscure strings I could think of to it, but it makes it through this, and errors out later on in the function..
[TestMethod]
//[ExpectedException(typeof(HttpResponseException))]
public void TestUploadCsv_UploadingCsvNonCsv()
{
const string csvText = "fhfhk#- jhjfh#ajh- fjkqeqir%hjewq#hf- ujewqh$phfuw \n hfwu- ihfq&if*u#q- afuhwu- fhiue#wfhiuewhiuf";
var context = GetMyFakeEntityDatabase();
var controller = new MyController(context);
controller.ParseCsv(csvText);
}
After the try/catch blocks, I have a section that enforces all the headers exist, and it fails there, but it should be failing during the reading, for this example. How do I force my unit test to fail? Any help is appreciated! Thanks in advance.
Use the Provider Pattern and interfaces instead of concrete types, then run your unit tests by substituting mock objects that will throw the exceptions.
In detail:
Extract Interface IXsvReader from XsvReader
Implement a new concrete instance of IXsvReader that throws exceptions on Read. Create one concrete implementation class for each error you expect to handle separately (in this case, you only need one).
In the class that contains the ParseCSV method, have a property for an IXsvProvider that is settable. In the constructor for that same class, set that property to a default provider that will return a "real" reader. This interface has only one method, GetXsvReader(string text)
In your test class, new up the class with the ParseCSV function, then inject an IXsvProvider(s) that returns your "dummy" IXsvReader that simply throws exceptions whenever you try to use the method.
You should use Inversion of Control and inject the dependency into the controller instead of creating it in controller action. This way you can mock out the reader, and have it throw an except instead.
I'm going to write this example in terms of CsvHelper since that's what you say you are using, even though the example doesn't look like it.
Roughly:
public class MyController : Controller
{
private readonly ICsvReader csv;
public MyController( ICsvReader csv )
{
this.csv = csv;
}
}
public class CsvReaderMock : ICsvReader
{
public void Read()
{
throw new Exception();
}
}
Now you can use your mock ICsvReader when testing, and it will throw an exception.
Also, you should only ever test a single method. If your method has dependencies, you should be passing them in instead of creating them, so you can test only the code in that method, and not of the classes it creates.
I solved this by just passing it null, like juharr recommended in the comments.
So basically, I have an abstract class which has a unique, incremental ID - Primitive. When a Primitive (or more precisely, an inheritor of Primitive) is instantiated, the ID is incremented - up to the point where the ID overflows - at which point, I add a message to the exception and rethrow.
OK, that all works fine... but I'm trying to test this functionality and I've never used mocking before. I just need to make enough Primitives for the ID to overflow and assert that it throws at the right time.
It is unreasonable to instantiate 2 billion objects to do this! However I don't see another way.
I don't know if I'm using mocking correctly? (I'm using Moq.)
Here's my test (xUnit):
[Fact(DisplayName = "Test Primitive count limit")]
public void TestPrimitiveCountLimit()
{
Assert.Throws(typeof(OverflowException), delegate()
{
for (; ; )
{
var mock = new Mock<Primitive>();
}
});
}
and:
public abstract class Primitive
{
internal int Id { get; private set; }
private static int? _previousId;
protected Primitive()
{
try
{
_previousId = Id = checked (++_previousId) ?? 0;
}
catch (OverflowException ex)
{
throw new OverflowException("Cannot instantiate more than (int.MaxValue) unique primitives.", ex);
}
}
}
I assume I'm doing it wrong - so how do I test this properly?
You don't need mocking for this. You use mocking when two classes work together and you want to replace one class with a mock (fake) one so you only have to test the other one. This is not the case in your example.
There is however a way you could use mocks, and that fixes your issue with the 2bln instances. If you separate the ID generation from the Primitive class and use a generator, you can mock the generator. An example:
I've changed Primitive to use a provided generator. In this case it's set to a static variable, and there are better ways, but as an example:
public abstract class Primitive
{
internal static IPrimitiveIDGenerator Generator;
protected Primitive()
{
Id = Generator.GetNext();
}
internal int Id { get; private set; }
}
public interface IPrimitiveIDGenerator
{
int GetNext();
}
public class PrimitiveIDGenerator : IPrimitiveIDGenerator
{
private int? _previousId;
public int GetNext()
{
try
{
_previousId = checked(++_previousId) ?? 0;
return _previousId.Value;
}
catch (OverflowException ex)
{
throw new OverflowException("Cannot instantiate more than (int.MaxValue) unique primitives.", ex);
}
}
}
Then, your test case becomes:
[Fact(DisplayName = "Test Primitive count limit")]
public void TestPrimitiveCountLimit()
{
Assert.Throws(typeof(OverflowException), delegate()
{
var generator = new PrimitiveIDGenerator();
for (; ; )
{
generator.GetNext();
}
});
}
This will run a lot faster and now you're only testing whether the ID generator works.
Now, when you e.g. want to test that creating a new primitive actually asks for the ID, you could try the following:
public void Does_primitive_ask_for_an_ID()
{
var generator = new Mock<IPrimitiveIDGenerator>();
// Set the expectations on the mock so that it checks that
// GetNext is called. How depends on what mock framework you're using.
Primitive.Generator = generator;
new ChildOfPrimitive();
}
Now you have separated the different concerns and can test them separately.
The point of the mock is to simulate an external resource. It's not what you want, you want to test your object, no mock needed in this szenario. Just instantiate the 2 billion objects if you like to, it doesn't hurt since the GC will throw away the old instances (but may take a while to complete).
Id' actually add another constructor which accepts a strarting value for the identity counter, so that you can actually start close to int.MaxValue and therefore don't need to instatiate as many objects.
Also, just from readin the source I can tell that your object will fail the test. ;-)
You have two problems baked into this question:
How to unit test an abstract class, that you can't instantiate.
How to efficiently unit test functionality that requires two billion instances to be created and destroyed.
I think the solutions are pretty simple, even though you'll have to re-think the structure of your object slightly.
For the first problem, the solution is as simple as adding a fake that inherits Primitive, but adds no functionality, to your test project. You can then instantiate your fake class instead, and you'll still be testing the functionality of Primitive.
public class Fake : Primitive { }
// and in your test...
Assert.Throws(typeof(OverflowException), delegate() { var f = new Fake(int.MaxValue); });
For the second problem, I'd add a constructor that takes an int for the previous ID, and use constructor chaining to "not need it" in your actual code. (But how to you get to know of the previous id otherwise? Can't you set that to int.MaxValue-1 in the setup of your test?) Think of it as dependecy injection, but you're not injecting anything complex; you're just injecting a simple int. It could be something along these lines:
public abstract class Primitive
{
internal int Id { get; private set; }
private static int? _previousId;
protected Primitive() : Primitive([some way you get your previous id now...])
protected Primitive(int previousId)
{
_previousId = previousId;
try
{
_previousId = Id = checked (++_previousId) ?? 0;
}
catch (OverflowException ex)
{
throw new OverflowException("Cannot instantiate more than (int.MaxValue) unique primitives.", ex);
}
}
All has been said in the other answers. I just want to show you an alternative, maybe this is somehow interesting for you.
If you made the _previousId field of your Primitive class internal (and included the respective InternalsVisibleTo attribute, of course), then your test could be as simple as this with the Typemock Isolator tool:
[Fact(DisplayName = "Test Primitive count limit"), Isolated]
public void TestPrimitiveCountLimit()
{
Primitive._previousId = int.MaxValue;
Assert.Throws<OverflowException>(() =>
Isolate.Fake.Instance<Primitive>(Members.CallOriginal, ConstructorWillBe.Called));
}
Sure, Typemock comes with some license costs, but it definitely makes life much easier and saves you a lot of time, if you have to write large amounts of test code - especially on systems which are not easily tested or are even impossible to test with a free mocking framework.
Thomas
I'm new to mocking/testing and wanting to know what level should you go to when testing. For example in my code I have the following object:
public class RuleViolation
{
public string ErrorMessage { get; private set; }
public string PropertyName { get; private set; }
public RuleViolation( string errorMessage )
{
ErrorMessage = errorMessage;
}
public RuleViolation( string errorMessage, string propertyName )
{
ErrorMessage = errorMessage;
PropertyName = propertyName;
}
}
This is a relatively simple object. So my question is:
Does it need a unit test?
If it does what do I test and how?
Thanks
it doesn't contain any logic => nothing to test
I would say probably not. The only thing that you would probably want to verify if it is extremely important are the access modifiers:
public string ErrorMessage { get; private set; }
public string PropertyName { get; private set; }
If it is really really important that code outside the class cannot modify them that might be the only thing I would try and verify.
Here is how you can get the accessors in a property:
class Program
{
static void Main(string[] args)
{
var property = typeof(Test).GetProperty("Accessor");
var methods = property.GetAccessors();
}
}
public class Test
{
public string Accessor
{
get;
private set;
}
}
With the property.GetAccessors();
You can see if the setter is there. If it is, then the setter is public. (There is also properties IsPrivate and IsPublic you can use to verify the other Accessors as well).
If it were my code and my object I would have tests for it, no matter how simple or complicated the class is, period. Even if the class seems unlikely to break, tests are where, IMO, you document your assumptions, design decisions, and proper usage.
By doing so, you not only validate that what you have works as intended, but you have the opportunity to think through typical scenarios (what happens if the ctor params are null or empty or have white space at the end? Why is the PropertyName optional in an immutable class?).
And IF (when?) requirements change you have a solid starting point for addressing that. And IF this trivial class somehow doesn't interact nicely with all of the other classes, you may have a test to catch that before your customers do.
It's just the right way to engineer your code.
HTH,
Berryl
You could unit test this object, but it's so simple as to not require it. The test would be something like (NUnit example)
[Test]
public void TestRuleViolationConstructorWithErrorMessageParameterSetsErrorMessageProperty() {
// Arrange
var errorMessage = "An error message";
// Act
var ruleViolation = new RuleViolation(errorMessage);
// Assert
Assert.AreEqual(errorMessage, ruleViolation.ErrorMessage);
}
There's little value to writing tests like these, however, as you are testing that the .NET framework's properties work correctly. Generally you can trust Microsoft to have got this right :-)
Regarding mocking, this is useful when your class under test has a dependency, perhaps on another class in your own application, or on a type from a framework. Mocking frameworks allow you call methods and properties on the dependecy without going to the trouble of building the dependency concretely in code, and instead allow you to inject defined values for properties, return values for methods, etc. Moq is an excellent framework, and a test for a basic class with dependency would look something like this:
[Test]
public void TestCalculateReturnsBasicRateTaxForMiddleIncome() {
// Arrange
// TaxPolicy is a dependency that we need to manipulate.
var policy = new Mock<TaxPolicy>();
bar.Setup(x => x.BasicRate.Returns(0.22d));
var taxCalculator = new TaxCalculator();
// Act
// Calculate takes a TaxPolicy and an annual income.
var result = taxCalculator.Calculate(policy.Object, 25000);
// Assert
// Basic Rate tax is 22%, which is 5500 of 25000.
Assert.AreEqual(5500, result);
}
TaxPolicy would be unit tested in its own fixture to verify that it behaves correctly. Here, we want to test that the TaxCalculator works correctly, and so we mock the TaxPolicy object to make our tests simpler; in so doing, we can specify the behaviour of just the bits of TaxPolicy in which we're interested. Without it, we would need to create hand-rolled mocks/stubs/fakes, or create real instances of TaxPolicy to pass around.
There's waaaaay more to Moq than this, however; check out the quick-start tutorial to see more of what it can do.
Even if simple, there's logic in your constructors. I would test that:
RuleViolation ruleViolation = new RuleViolation("This is the error message");
Assert.AreEqual("This is the error message", ruleViolation.ErrorMessage);
Assert.IsEmpty(ruleViolation.PropertyName);
RuleViolation ruleViolation = new RuleViolation("This is the error message", "ThisIsMyProperty");
Assert.AreEqual("This is the error message", ruleViolation.ErrorMessage);
Assert.AreEqual("ThisIsMyProperty", ruleViolation.PropertyName);
In the code base I was maintaining I found this exact class, pasted below. In logPath property, gets does some work. I would think that it is better to do the work in set - that way it will be done only once. However, partly because this is how the class is written, partly because it is an xml-mapped property, and partly because I am afraid that I might miss something in a debugger, I have doubts.
Additionally, if an element never existed in the xml, and it happened to be optional, then I think I will get a null for the value. I might actually want to differentiate between having no element and receiving empty value. I suppose I can have a private bool member which can help me detect that - that would be an argument for doing work in set rather than get. So, code optimizers work hard these days, so performance is rarely a true concern. It is more of a "figure this out once and do not think about it later" things. This is just one example, and properties frequently do some massaging.
Would you say that it is always better to do work in set? In get? It depends? A mixed style would not bother you a single bit as long as it works?
Thanks.
namespace MyNamespace
{
using System;
using System.Xml.Serialization;
/// <summary>
/// The LoggingListener class encapsulates the "logListener"
/// element of config file, and puts the "logPath"
/// attribute in a file path string.
/// </summary>
public class LoggingListener
{
private string logPathValue;
/// <summary>
/// Gets or sets the LOCAL file path to a log file
/// which will be written during operation of the Updater.
/// </summary>
[XmlAttribute("logPath")]
public string LogPath
{
get
{
return this.logPathValue == null ?
String.Empty : this.logPathValue;
}
set
{
this.logPathValue = value;
}
}
}
}
EDIT: In this given sample ... if the log file is not there, then no logging should take place.
I'd certainly prefer consistency. But the fact is in cases like this it often will not matter. I'm sure the original developer's intent was to avoid the infuriating NullReferenceException bug resulting from attempting to access the LogPath property of some LoggingListener object -- in which case, it probably just seemed most sensible to put the null check in the get (since that's where the exception was thrown).
In general, I'd agree with you that perhaps it makes the most sense to put it in the set -- but then, there's no guaranteeing LogPath will never return null, as the private member could have been set to null from within the class, or perhaps it was never set at all (as Kevin pointed out).
I tend to go with a somewhat hybrid approach: make the property read-only, and make sure it gets set to something non-null in the constructor:
public class LoggingListener {
private readonly string _logPath;
public LoggingListener(string logPath) {
_logPath = logPath ?? string.Empty;
}
public string LogPath {
get { return _logPath; }
}
}
Whether this is an acceptable compromise obviously depends on your specific needs. Also, whether the property should really never be null after all is certainly debatable, depending on the scenario, as you've already remarked.
I personally don't like when property changes assigned value in either get or set accessor. It changes expected property behavior:
var value = null;
var listener = new LoggingListener();
listener.LogPath = value;
if(listener.LogPath != value)
{
// how could we get here?
}
Instead, I prefer to clearly decide, whether property can accept null or not. If it can, it shouldn't do any work in get/set, if yes, it should neither return null nor accept it as a value.
If there is no way to prevent assignment of null, than i would prefer to handle this case in set accessor.
With getters and setters I follow a few rules:
No side effects - don't modify 'B' when you put a value in 'A'
What I put in 'A' comes out of 'A', if you need to modify 'A' expose a new read-only property
If you don't like my value for 'A', tell me now not later when I call a method
Outside of a data model, do not accept or return null
For your example I prefer seeing the following:
public class LoggingListener
{
private string logPathValue = String.Empty;
[XmlAttribute("logPath")]
public string LogPath
{
get { return logPathValue; }
set
{
if(value == null) throw new ArgumentNullException();
this.logPathValue = value;
}
}
}
Yet it's clear to me why you ask, it really about the behavior of "XmlAttribute" and the XmlSerializer. You can use the "DefaultValueAttribute" from the ComponentModel namespace, or use an XSD to provide the defaults, or expose a new property and/or method. You could also try creating an interface to separate concerns, something like the following:
public class LoggingListener : ILogListenerSettings
{
private string logPathValue;
[XmlAttribute("logPath")]
public string LogPath
{
get { return logPathValue; }
set { logPathValue = value; }
}
string ILogListenerSettings.FullLogPath
{
get
{
string path = logPathValue;
if(String.IsNullOrEmpty(path))
path = Environment.CurrentDirectory;
path = Path.GetFullPath(path);
Directory.Create(path);
return path;
}
}
}
the only way to be sure that logPathValue is initialized is to do it yourself...
public class LoggingListener
{
private string logPathValue = string.Empty;