I have a test method that tests the ToString() method of a class against known good outputs.
/// <summary>
///A test for ToString
///</summary>
[TestMethod()]
public void ToStringTest()
{
string input = System.IO.File.ReadAllText(#"c:\temp\input2005.txt");
MyClass target = new MyClass(input);
string expected = System.IO.File.ReadAllText(#"c:\temp\output2005.txt");
string actual;
actual = target.ToString();
Assert.AreEqual(expected, actual);
}
The method works great, but I already have several pairs of input/output files. Experience tells me that I don't want to write a separate test method for each pair. I also don't want to loop through each pair of files because I won't know which pair caused the test to fail. What do I do?
You could use a loop inside your test but you will only get one pass or failure for all of them. Some test frameworks will generate and run a separate test for each set of inputs specified like this:
[Test]
[Row(#"c:\temp\input2005.txt", #"c:\temp\output2005.txt")]
[Row(#"c:\temp\input2006.txt", #"c:\temp\output2006.txt")]
[Row(#"c:\temp\input2007.txt", #"c:\temp\output2007.txt")]
public void ToStringTest(string inputPath, string expectedPath)
{
string input = System.IO.File.ReadAllText(inputPath);
MyClass target = new MyClass(input);
string expected = System.IO.File.ReadAllText(expectedPath);
string actual;
actual = target.ToString();
Assert.AreEqual(expected, actual);
}
The above will work with MbUnit but I believe many of the other frameworks also support similar features.
As an aside, unit tests shouldn't really touch the file system as you can get test failures due to external factors (such as a file being locked) which makes your tests unreliable.
If you wish to test all pairs of files, you could put the file that failed as a message to the assertion:
foreach(file in filenames)
{
/* run your test */
Assert.AreEqual(expected, actual, "Failure occured on file: " + file);
}
This would print out a message telling you which file the failure occured on.
Additionally, you could specify your strings inside of the test itself instead of putting them in extrenal files. I'm not sure how your tests are setup but if you did that you wouldn't have to worry about the external depencies of the file paths:
MyClass target = new MyClass("myTestString");
string actual = target.ToString();
string expected = "MyExpectedString";
Assert.AreEqual(expected, actual);
This would keep all of your test data together.
The MbUnit framework has the concept of row tests and I believe there is an NUnit Add-In for 2.4 that provides similar functionality for NUnit. Using MbUnit syntax it would look something like this:
/// <summary>
///A test for ToString
///</summary>
[Test]
[RowTest(#"c:\temp\input2005.txt", #"c:\temp\output2005.txt")]
[RowTest(#"c:\temp\input2006.txt", #"c:\temp\output2006.txt")]
[RowTest(#"c:\temp\input2007.txt", #"c:\temp\output2007.txt")]
public void ToStringTest(string inputFile, string outputFile)
{
string input = System.IO.File.ReadAllText(inputFile);
MyClass target = new MyClass(input);
string expected = System.IO.File.ReadAllText(outputFile);
string actual;
actual = target.ToString();
Assert.AreEqual(expected, actual);
}
Related
I use NSubstitute for my NUnit tests and try to check if a method is called with the right values. Until know everything works fine. I have to localize the texts and so use resource strings for this. Every unit test now fails, that tests for a method to be recieved, where a string parameter contains a new line.
Here is a simplified example:
// Old Version, where the unit test succeed
public void CallWithText(ICallable callable)
{
callable.ShowText("Some text with a new\nline.");
}
// New Version, where the unit test fails
// Text of `Properties.Resources.TextWithNewLine` in the
// Resources.resx is "Some text with a new
// line."
public void CallWithText(ICallable callable)
{
callable.ShowText(Properties.Resources.TextWithNewLine);
}
[Test]
public void CallWithText_WhenCalled_CallsCallable()
{
var caller = new Caller();
var callable = Substitute.For<ICallable>();
caller.CallWithText(callable);
callable.Received(1).ShowText("Some text with a new\nline.");
}
It seems for me, that there is a problem with the new line. Does anybody has a solution, because it is a mess to adapt all the unit tests.
The problem isn't related to NSubstitute but to String itself. The new line symbol isn't just \n. It's environment specific: \r\n on Windows, \n on Unix, \r on early Mac OSes. Please use Shift+Enter to add new lines properly in Resource manager.
You have a couple of ways to use:
Environment.NewLine property which knows the new line symbol for the current environment:
callable.Received(1).ShowText("Some text with a new" + Environment.NewLine + "line.");
Use explicit new line in your expected string:
callable.Received(1).ShowText(#"Some text with a new
line.");
Comparing exact strings in the unit test will add more maintaining work.
In your case new line can be different in different execution environment.
For strings I suggest asserting passed parameter with Contains method. Where you can check for the more important words
[Test]
public void CallWithText_WhenCalled_CallsCallable()
{
var caller = new Caller();
var callable = Substitute.For<ICallable>();
caller.CallWithText(callable);
callable.Received(1).ShowText(Arg.Is<string>(text => text.Contains("Some text")));
}
This indicates the Properties.Resources.TextWithNewLine and "Some text with a new\nline." and different. Without knowing too much about Properties.Resources.TextWithNewLine, I suggest you try change the test to
[Test]
public void CallWithText_WhenCalled_CallsCallable()
{
var caller = new Caller();
var callable = Substitute.For<ICallable>();
caller.CallWithText(callable);
callable.Received(1).ShowText(Arg.Any<string>());
}
Or use the actual string if you really want to assert the content of the string, change to (make sure the resources file is in the test project)
[Test]
public void CallWithText_WhenCalled_CallsCallable()
{
var caller = new Caller();
var callable = Substitute.For<ICallable>();
caller.CallWithText(callable);
callable.Received(1).ShowText(Properties.Resources.TextWithNewLine);
}
Trying to create unit tests for my methods and can't seem to get the configuration right.
I go New Test -> Unit Test Wizard -> Pick my method -> fill in test method values but I always get Assert.Inconclusive failed. Verify the correctness of this test method.
Here is a sample method:
namespace ConsoleApplication
{
class Program
{
static void Main(string[] args)
{
}
public int Mult(int a, int b)
{
return a * b;
}
}
}
and the test method:
[TestMethod()]
public void MultTest()
{
Program target = new Program(); // TODO: Initialize to an appropriate value
int a = 4; // TODO: Initialize to an appropriate value
int b = 5; // TODO: Initialize to an appropriate value
int expected = 20; // TODO: Initialize to an appropriate value
int actual;
actual = target.Mult(a, b);
Assert.AreEqual(expected, actual);
Assert.Inconclusive("Verify the correctness of this test method.");
}
Seems straight forward enough, but am I missing something trivial?
The Assert.Inconclusive is mainly a marker to tell you that you need to right your own verification steps for the test method. In other words, for what you are doing it can be removed as you have added your own Assertion.
It could also be used, if there is some logic in your test that prevents the full running of your test. So, if, for example, you couldn't create the object you were trying to test for some reason.
sure you do :
Assert.Inconclusive("Verify the correctness of this test method.");
Your test says inconclusive therfore the result of the test is inconclusive.. You should use this syntax "Assert.Inconclusive" only to cover edge cases you are really aware of.
AFAIC, I never use it.
If I have a function which accepts an out parameter and accepts an input form console -
public void Test(out int a)
{
a = Convert.ToInt16(Console.ReadLine());
}
How can I accept an input using Console.Readline() during NUnit test? How can I use NUnit to test this method?
I tried using this code for my NUnit test case -
[TestCase]
public void test()
{
int a = 0;
ClassAdd ad = new ClassAdd();
ad.addition(out a);
//a should be equal to the value I input through console.Readline()
Assert.AreEqual(<some value I input>, a, "test");
}
how can I test a method which accepts an out parameter and also accepts an user input from Console?
You can use the SetIn method of System.Console to set the the input source:
StringReader reader = new StringReader("some value I input" + Enivronment.NewLine);
Console.SetIn(reader);
int a = 0;
ClassAdd ad = new ClassAdd();
ad.addition(out a);
Assert.AreEqual(<some value I input>, a, "test");
EDIT: To test multiple values, just separate each input with a new line:
string[] lines = new[] { "line1", "line2" };
StringReader input = new StringReader(String.Join(Environment.NewLine, lines));
Console.SetIn(input);
string input1 = Console.ReadLine(); //will return 'line1'
string input2 = Console.ReadLine(); //will return 'line2'
There are 2 slightly different issues combined here.
You want to test a method that returns a value in an out parameter. This is actually quite trivial and is hardly different from a method that returns its value as a normal function.
You want to test a method that reads input form the console. This one is quite a bit trickier, and goes a little into the design of the object you're trying to test. The problem is that the "Console" is a global object, and that immediately makes it more difficult to test.
The craziest thing to note is that you want to test a method that takes input from the console. I.e. this implies user interaction. This is hardly the way to go about "automated testing" don't you think?
In answer to #2, I suggest you look at some of Misko Hevery's articles and videos on writing testable code.
http://misko.hevery.com/2008/08/21/where-have-all-the-singletons-gone/
For a brief summary specfic to your problem:
MethodToTest currently wants input from the console.
The class that holds MethodToTest should take an "input stream" in its constructor. (This is a technique called dependency injection.)
In production code, your class will be created with the normal "Console" as its input stream.
In test code, the class will be constructed with a Mock input stream that will feed values controlled by the test.
In this way your test can be automated, and well controlled in terms of inputs; and therefore expected outputs.
Bare Bones Sample Code
[TestCase]
public void test()
{
<use appropriate type here> MockInputStream = new ...;
ClassToTest testClass = new ClassToTest(MockInputStream);
int Actual = 0;
MockInputStream.PutNextInput("4");
ClassToTest.MethodToTest(out Actual);
Assert.AreEqual(4, Actual, "MockInputStream placed 4 as the next value to read");
}
I want to capture output sent to standard out and standard error within an MSTest unit test so that I can verify it. I've captured output before when explicitly running a Process, but is there a way to do with [I guess] the MSTest process itself? For example:
[TestMethod]
public void OutputTest()
{
MySnazzyMethod("input", 1, 'c');
string stdOutFromMySnazzyMethod = /* ??? */;
Assert.AreEqual("expected output", stdOutFromMySnazzyMethod);
}
I'm not sure there is a way to grab the output of an already running Process. What you could do though is refactor your code slightly to not write to Console.WriteLine but instead take in a TextWriter instance and write to that.
In production you can then just pass Console.Out to the method. In test code you could mock this type and provide much more accurate testing. For example
[TestMethod]
public void OutputTest()
{
var writer = new Mock<TextWriter>(MockBehavior.Strict);
writer.Setup(x => x.WriteLine("expected output")).Verifiable();
MySnazzyMethod(writer.Object, "input", 1, 'c');
writer.Verify();
}
Production Code
MySnazzyMethod(Console.Out, "input", 1, 'c');
I liked JaredPar's idea but I didn't want to pass in Console.Out and Console.Error to every helper output method I had. However, my output does go through a single class, so I just set a couple static fields in it:
internal static TextWriter _stdOut = Console.Out;
internal static TextWriter _stdErr = Console.Error;
I updated my output methods in the output handler class to make use of these fields. I then updated that project's AssemblyInfo.cs to include:
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("MyTestProject")]
This way, I can override _stdOut and _stdErr in my test methods, call my method to be tested (which uses my output handling class), and confirm the output I expected.
OutputHandler._stdOut = new StringWriter();
MySnazzyMethod("input", 1, 'c');
OutputHandler._stdOut.Flush();
string expected = "expected output";
string stdout = OutputHandler._stdOut.ToString().Trim(new[] { '\r', '\n' });
Assert.IsFalse(string.IsNullOrEmpty(stdout));
Assert.AreEqual(expected, stdout);
Just add a couple TraceListener in the class initialize of your test classes.
I'd use Moles to redirect the call to Console writes to a lambda method inside your test code.
string result = "";
System.Moles.MConsole.WriteLineString = (s) =>
{ result = s; };
Assert.IsTrue(result == "The string I want",
"Failed to write to console correctly");
See page 16 in this document: Moles Reference Manual.
So' I'm getting in Unit Testing. I created a really simple Function to test it.
public int MultiplyByFive(int x)
{
return x * 5;
}
The Test Method contains
[TestMethod()]
[DeploymentItem("UnitTestApp.exe")]
public void MultiplyByFiveTest()
{
Program_Accessor target = new Program_Accessor(); // TODO: Initialize to an appropriate value
int x = 5; // TODO: Initialize to an appropriate value
int expected = 25; // TODO: Initialize to an appropriate value
int actual;
actual = target.MultiplyByFive(x);
Assert.AreEqual(expected, actual);
Assert.Inconclusive("Verify the correctness of this test method.");
}
But when I run the test it returns:
nunit http://dl.getdropbox.com/u/357576/nunit.jpg
"Assert.Inconclusive failed. Verify the correctness of this test method."
So what I'm doing wrong? thanks!
NUnit 2.5 added "inconclusive" as a result state in between success and failure. It's explained in the release notes here.
NUnit is doing exactly what you told it to do. The new inconclusive state does terminate the test. If you want a message displayed in the case of your Assert failing, Assert.AreEqual() has an overload that takes a message string. Use that, and remove Assert.Inconclusive().
Assert.AreEqual(expected, actual, "Verify the correctness of this test method.");
You need to remove the Assert.Inconclusive if you are certain your test is correct :)