Methods adapted to satisfy unit tests. This just seems wrong - c#

I have begun to dabble in unit testing, and have created a couple of tests that test one of my presenter methods. This testing requires a mock of my data access class, and one method in particular. This is the original method from my data access class:
public IEnumerable<IArea> GetAreaList()
{
ConnectToTFSProject();
XmlNode areaNode = GetAreaNode();
List<IArea> areaList = new List<IArea>();
foreach (XmlNode node in areaNode.FirstChild.ChildNodes)
{
IArea area = new Area() { AreaName = node.Attributes["Name"].Value };
areaList.Add(area);
}
areaList.Sort();
return areaList;
}
I would like to test the presenter method with different scenarios, e.g.:
a regular list of areas
an empty list of areas
a list of areas with duplicates
a list or areas containing one empty string area
My first thought was to create a separate mock data access class for each of these scenarios. I thought this to be a little cumbersome, so I adapted the method slightly to allow the reading of different xml files, containing data specific to the current test. Here is how my mock method looks:
public IEnumerable<IArea> GetAreaList(string dataSource)
{
List<IArea> areaList = new List<IArea>();
XmlTextReader areaReader = new XmlTextReader(dataSource);
while (areaReader.Read())
{
if (areaReader.NodeType == XmlNodeType.Text)
areaList.Add(new Area() { AreaName = areaReader.Value });
}
return areaList;
}
This mock method will then be called from the PresenterTest class as follows:
[TestMethod]
public void PopulateAreaComboBox_WithValidAreaList()
{
//Act
_presenter.PopulateAreaComboBox(mockFolderPath + "MockAreaList.xml");
//Assert
Assert.AreEqual(3, _view.AreaListLoaded.Count);
}
[TestMethod]
public void PopulateAreaComboBox_WithEmptyAreaList()
{
//Act
_presenter.PopulateAreaComboBox(mockFolderPath + "MockEmptyAreaList.xml");
//Assert
Assert.AreEqual(0, _view.AreaListLoaded.Count);
}
Now, the problem I have here is that I now need to change the signature of my original method (by adding reference to the dataSource parameter):
public IEnumerable<IArea> GetAreaList(string dataSource)
Because this parameter is required only for the unit tests, the value of null is passed into this method from the real presenter class, and never used.
I know this is wrong but how should this be accomplished? Should I create a separate mock data access class that sets up each test data scenario?

I resolved this by exposing a public string (TestDataXml) in my mock data access class. I then created a new instance of the mock data access class for each test, setting this string to the location of an individual test data xml file each time:
class MockDataRetrieval : IDataRetrieval
{
public string TestDataXml { get; set; }
public IEnumerable<IArea> GetAreaList()
{
List<IArea> areaList = new List<IArea>();
XmlTextReader areaReader = new XmlTextReader(TestDataXml);
while (areaReader.Read())
{
if (areaReader.NodeType == XmlNodeType.Text)
areaList.Add(new Area() { AreaName = areaReader.Value });
}
return areaList;
}
}
To call the mock method from the PresenterTest class:
[TestMethod]
public void PopulateAreaComboBox_WithValidAreaList()
{
//Arrange
_data = new MockDataRetrieval() { TestDataXml = mockFolderPath + "MockAreaList.xml" };
_view = new MockMainForm();
_presenter = new TestCasePresenter(_view, _data);
//Act
_presenter.PopulateAreaComboBox();
//Assert
Assert.AreEqual(3, _view.AreaListLoaded.Count);
}
[TestMethod]
public void PopulateAreaComboBox_WithEmptyAreaList()
{
//Arrange
_data = new MockDataRetrieval() { TestDataXml = mockFolderPath + "MockEmptyAreaList.xml" };
_view = new MockMainForm();
_presenter = new TestCasePresenter(_view, _data);
//Act
_presenter.PopulateAreaComboBox();
//Assert
Assert.AreEqual(0, _view.AreaListLoaded.Count);
}
Ralf: Thanks for your comment. This question relates to testing the Presenter.PopulateAreaComboBox method. The GetAreaList method in this example is from the mock data access class, and simply provides the method under test with test data.

Related

Testing a property set to an instance of a new object in Rhino Mocks 3.4.0

Background
I'm fixing unit tests which have been neglected for a long time for legacy code in our organisation. They're written using Rhino Mocks 3.4.0, and I'm struggling to find a way of making this test pass. Rhino Mocks documentation seems to have gone, and most answers here and blogs seem to be using updated 3.5 and 3.6 syntax.
I'm wary of updating the version of Rhino Mocks we're using, as we have several thousand unit tests which may or may not need updated if we update.
The scenario:
We have a Presenter and a View. When the Presenter is initialised, it sets some default filter properties in the View. In the past, both of these properties were enums and the test passed.
The last change updated one of the properties to be an instance of a class. The test was updated to expect a call to a static method which creates an instance with default values (matching the code under test), but the test now fails with the error Rhino.Mocks.Exceptions.ExpectationViolationException : Unordered method call.
Some sample code:
public enum FilterOptions { OptionA, OptionB, OptionC }
public class OtherFilterOptions
{
public bool Filter1 { get; set;}
public bool Filter2 { get; set; }
public OtherFilterOptions(bool filter1 = true, bool filter2 = false)
{
Filter1 = filter1;
Filter2 = filter2;
}
public static OtherFilterOptions DefaultFilterOptions()
{
return new OtherFilterOptions();
}
}
public interface IToTestView
{
FilterOptions Property1 { set; }
OtherFilterOptions Property2 { set; }
}
public class ToTestPresenter
{
public IToTestView View { get; set; }
public ToTestPresenter(IToTestView view)
{
View = view;
}
public void InitialiseView()
{
View.Property1 = FilterOptions.OptionA;
View.Property2 = OtherFilterOptions.DefaultFilterOptions();
}
}
And a failing test:
[TestFixture]
class Tests
{
[Test]
public void TestOne()
{
var mocks = new MockRepository();
var mockView = mocks.CreateMock<IToTestView>();
ToTestPresenter presenter = new ToTestPresenter(mockView);
using (mocks.Ordered())
{
mockView.Property1 = FilterOptions.OptionA;
mockView.Property2 = OtherFilterOptions.DefaultFilterOptions();
}
mocks.ReplayAll();
presenter.InitialiseView();
mocks.VerifyAll();
}
}
The full error is
Rhino.Mocks.Exceptions.ExpectationViolationException : Unordered method call! The expected call is: 'Ordered: { IToTestView.set_Property2(RhinoMocksTestApp.OtherFilterOptions); }' but was: 'IToTestView.set_Property2(RhinoMocksTestApp.OtherFilterOptions);'
I'm assuming that the test is failing because the value to be set is a method call rather than a concrete value. I've tried declaring a variable using mockView.Property2 = theVariable, but there's no change to the error.
Can I set an expectation that Property2 will be set to {some object with Values Filter1 = true, Filter2 = false}? I've seen examples doing similarly using Rhino Mocks 3.6, but is anything available using 3.4.0?
Edit:
As an example, this is an example test which passes in Rhino Mocks 3.6.1 - I'm hoping to find some syntax that works similarly for 3.4.0, if it exists.
[Test]
public void TestOne()
{
var mocks = new MockRepository();
var mockView = MockRepository.GenerateMock<IToTestView>();
ToTestPresenter presenter = new ToTestPresenter(mockView);
mocks.ReplayAll();
presenter.InitialiseView();
mockView.AssertWasCalled(v => v.Property1 = FilterOptions.OptionA);
mockView.AssertWasCalled(v => v.Property2 = Arg<OtherFilterOptions>.Matches(filters =>
(filters.Filter1 == true) && (filters.Filter2 == false)));
}
The answer I was looking for was in the LastCall.Constraints() method. Passing arguments to Constraints allows you to specify property values of an argument:
[Test]
public void TestOne()
{
var mocks = new MockRepository();
var mockView = mocks.CreateMock<IToTestView>();
ToTestPresenter presenter = new ToTestPresenter(mockView);
using (mocks.Ordered())
{
mockView.Property1 = FilterOptions.OptionA;
mockView.Property2 = OtherFilterOptions.DefaultFilterOptions();
LastCall.Constraints(
Property.Value("Filter1", true)
& Property.Value("Filter2", false));
}
mocks.ReplayAll();
presenter.InitialiseView();
mocks.VerifyAll();
}
There are a large number of options that can be passed in to the Constraints() method. Details on some of them on this CodeProject page
Another option is LastCall.IgnoreArguments() if you don't care what the property is actually set to.

How should I unit test multiple required fields in C#?

Imagine this simple scenario: I have a class called MyModel:
public class MyModel
{
public string Prop01 { get; set; }
public string Prop02 { get; set; }
public string Prop03 { get; set; }
public bool IsValid()
{
if (String.IsNullOrEmpty(Prop01) || String.IsNullOrEmpty(Prop02) || String.IsNullOrEmpty(Prop03))
return false;
return true;
}
}
As, you can see, if any of the properties on MyModel is null or empty, the IsValid() method will return false, in other words, all the fields are "required".
I wrote some Unit Tests to test the IsValid() method:
[TestMethod]
public void MyModel_Invalid_When_Prop01_Is_Null()
{
var myModel = new MyModel();
Assert.AreEqual(myModel.IsValid(), false);
}
[TestMethod]
public void MyModel_Invalid_When_Prop02_Is_Null()
{
var myModel = new MyModel();
Assert.AreEqual(myModel.IsValid(), false);
}
[TestMethod]
public void MyModel_Invalid_When_Prop03_Is_Null()
{
var myModel = new MyModel();
Assert.AreEqual(myModel.IsValid(), false);
}
Of course all those tests will pass, but I'm not quite happy with that. Let's imagine I'm a developer that saw the MyModel_Invalid_When_Prop01_Is_Null test (that was writen by another developer). I would expect that just by assigning a value to the Prop01 of myModel, the test should start failing. But of course it won't happen, so I changed the tests to look like this:
[TestMethod]
public void MyModel_Invalid_When_Prop01_Is_Null()
{
var myModel = new MyModel();
myModel.Prop02 = "Some value";
myModel.Prop03 = "Some value";
Assert.AreEqual(myModel.IsValid(), false);
}
[TestMethod]
public void MyModel_Invalid_When_Prop02_Is_Null()
{
var myModel = new MyModel();
myModel.Prop01 = "Some value";
myModel.Prop03 = "Some value";
Assert.AreEqual(myModel.IsValid(), false);
}
[TestMethod]
public void MyModel_Invalid_When_Prop03_Is_Null()
{
var myModel = new MyModel();
myModel.Prop01 = "Some value";
myModel.Prop02 = "Some value";
Assert.AreEqual(myModel.IsValid(), false);
}
Now the tests are really testing that each of the properties are filled, but if I add a Prop04 to MyModel, that is also required field, I would need to change all my Unit Tests again, so I don't think this is a good idea.
So my question is: How can I unit test multiple required properties in a way that I'm sure the test is either passing or failing because of that specific property I'm currently testing? Or maybe, Should I be testing those scenarios?
Instead of starting with an empty, invalid model, you could start with a valid one and then make it invalid. That will make sure you only have to modify your tests in one place, which is fine, because your actual requirements changed.
An added advantage is that your tests become more explicit, because the setup is explicitly making your model invalid:
[TestMethod]
public void MyModel_Invalid_When_Prop01_Is_Null()
{
var myModel = getValidModel();
myModel.Prop01 = null;
Assert.AreEqual(myModel.IsValid(), false);
}
[TestMethod]
public void MyModel_Invalid_When_Prop02_Is_Null()
{
var myModel = getValidModel();
myModel.Prop02 = null;
Assert.AreEqual(myModel.IsValid(), false);
}
[TestMethod]
public void MyModel_Invalid_When_Prop03_Is_Null()
{
var myModel = getValidModel();
myModel.Prop03 = null;
Assert.AreEqual(myModel.IsValid(), false);
}
MyModel getValidModel() =>
new MyModel
{
Prop01 = "Some value",
Prop02 = "Some value",
Prop03 = "Some value",
};
If your model initialization becomes more complex, you could make use of the builder pattern.
I wrote a blog-post about this which may be helpful: https://www.kenneth-truyers.net/2013/07/15/flexible-and-expressive-unit-tests-with-the-builder-pattern/
In my opinion, if isValid() is important enough to be a method then it's important enough that its behavior should be tested.
In some ways the simplicity of its logic may lull you into feeling it can't be worth all the work. Well, I get it, but the counter-argument is if someone adds another required field, failing to update isValid() is a very plausible mistake; and if you're not testing the behavior if isValid() then you won't know until some mysterious production bug where nobody thinks to look for Prop04 to be Null because hey, isValid() returns true...
So yes, I'd test it; but yes, you can make that easier. You could create a single helper function in your test class that produces a dummy instance of the MyModel with all fields populated. Then your test methods just look like
(Pardon any code typos; I'm not at a compiler but I think you'll see what I mean...)
[TestMethod]
public void MyModel_Invalid_When_Prop01_Is_Null()
{
var myModel = getMyModelInstance();
myModel.Prop01 = Null;
Assert.AreEqual(myModel.IsValid(), false);
}
And of course you'd have another test method that doesn't set any of the properties to Null and asserts that IsValid() should return true.
So now you add a new property, you add a new test method (which you'd expect to have to do). You update the helper to populate the new property; you'd need that to support the "IsValid() is true" case anyway. And so none of the other existing test methods needs updating.

Unit Test for two classes inherit an Interface

I have two classes that implement an interface, but both classes have a parameter passed into the constructor to identify what class the application would need. I am trying to test one (GetAvailablity) method on (AvailablityRepoData) class when I create an instance of AvailablityRepoData I am getting an error for non-virtual method. I would really appreciate if someone can point me to the right direction.
public interface IAvailablityRepo
{
string GetAvailablity(Availablity availablity);
}
public class AvailablityRepoData: IAvailablityRepo
{
public AvailablityRepoData(string websetting) {
}
public string GetAvailablity(Availablity availablity) {
return "Data";
}
}
public class AvailablityRepoWeb:IAvailablityRepo
{
public AvailablityRepoWeb(string DataSetting) {
}
public string GetAvailablity(Availablity availablity) {
return "Web";
}
}
public class Availablity
{
public virtual string Id {
get;
set;
}
public virtual string Status {
get;
set;
}
}
var a = new Availablity() { Id = "111", Status = "A"};
Mock<IAvailablityRepo> mockRepo = new Mock<IAvailablityRepo>();
Mock<IAvailablityRepo> RepoData = new Mock<IAvailablityRepo>();
RepoData.Setup(x => x.GetAvailablity(It.IsAny<Availablity> ())).Returns("pass");
var result = RepoData.Object.GetAvailablity(a);
As has already been said in the comments, it's not clear from the code you've posted what your error is. If I copy and past it straight into visual studio (wrapping the test code in a test), the test passes fine. I'm going to suggest that when you experienced the error, you test code was actually closer to this:
[TestMethod]
public void TestMethod1() {
var a = new Availablity() { Id = "111", Status = "A" };
Mock<IAvailablityRepo> mockRepo = new Mock<IAvailablityRepo>();
Mock<AvailablityRepoData> RepoData = new Mock<AvailablityRepoData>();
RepoData.Setup(x => x.GetAvailablity(It.IsAny<Availablity>())).Returns("pass");
var result = RepoData.Object.GetAvailablity(a);
}
This results in an error when the test is run:
System.NotSupportedException:Invalid setup on a non-virtual (overridable in VB) member:
x => x.GetAvailablity(It.IsAny<Availablity>())
The difference between this test and your original test is that I've changed the Mocked type from the interface IAvailabilityRepo to AvailabilityRepoData which is the concrete class. Since Moq only supports mocking of interfaces / virtual methods it's naturally getting upset.
As has been mentioned by #prgmtc, your test as it stands doesn't really testing much of anything.
With your current code, it doesn't actually look like you need to be using Mocks at all. Something like this might be a more appropriate test:
[TestMethod]
public void TestDataRepoReturnsDataAvailability() {
var someImportantSetting = "thisShouldBeSomethingMeaningful";
var availability = new Availablity() { Id = "111", Status = "A" };
var sut = new AvailablityRepoData(someImportantSetting);
var returnedAvailability = sut.GetAvailablity(availability);
Assert.AreEqual("Data", returnedAvailability);
}
Assuming your actual code is more complex the string passed into your data repo would presumably need to be rather more meaningful...
As a general rule of thumb, you shouldn't be mocking the system under test. If you find yourself creating a mock for the system you're testing it's a good indication that you've got to much functionality in one class and/or you're trying to test the wrong thing...
As an asside, you may want to look into something like the builder pattern to create your different repos rather than passing the type into the constructor for each of the repos as you seem to be suggesting.

Writing NUnit Test Cases for method

i am new for Nunit.please help for write a test case.
this is my class
public CommandModule(ICommandFetcher fetcher,ICommandBus commandBus)
{
//Get["/"] = p =>
//{z
// return Response.AsText((string)Request.Form.Username);
//};
Post["/"] = parameters =>
{
var commandRequest = this.Bind<MessageEnvelope>();
var command = fetcher.FetchFrom(commandRequest);
commandBus.Send((ICommand)command, commandRequest.MetaData);
return HttpStatusCode.OK;
};
}
}
and i want to test for check this method
commandBus.Send((ICommand)command, commandRequest.MetaData);
thank you!
i try it following way
[Test]
public void whern_reseiving_command_it_sent_to_the_command_bus()
{
var rCommand = new DummyCommand() { SomeProp = 2 };
var serializedCommand = JsonConvert.SerializeObject(rCommand);
var envelope = new MessageEnvelope() { MetaData = new MetaData() { MessageType = "DummyCommand", MessageTypeVersion = 1 }, MessageData = serializedCommand };
var fakeCommand = A.Fake<ICommandBus>();
var browser = new Browser(with =>
{
with.Module<CommandModule>();
with.Dependency<ICommandBus>(fakeCommand);
});
var result = browser.Post("/", with =>
{
with.HttpRequest();
with.JsonBody(envelope);
});
A.CallTo(() => fakeCommand.Send(rCommand,envelope.MetaData)).MustHaveHappened();
but A.CallTo(() => fakeCommand.Send(rCommand,envelope.MetaData)).MustHaveHappened();
it has some kind of error in rcommand value
It sounds like you are looking to explicitly test that ICommandBus.Send is called when your code is executed.
One approach is to mock the ICommandBus dependency. That is, insert a mock object implementing ICommandBus that is able to detect whether that method is called with the right parameter values.
If you take this approach, you would normally do this using a mocking framework (e.g. Moq, or RhinoMocks).
To explain how you would use a mock for this briefly, I will show how you can do this by by explicitly implementing a mock object object yourself that records method calls, and testing them afterwards.
E.g.
MockCommandBus : ICommandBus
{
ICommand PassedCommand { get; set; }
MetaData PassedMetaData { get; set; }
public void Send(ICommand command, MetaData metaData)
{
this.PassedCommand = command;
this.PassedMetaData = metaData;
}
}
Then your test case will look like this:
[TestCase]
public void PostSendsCommandOnBus()
{
// ARRANGE
var mockCommandBus = new MockCommandBus();
ICommand expectedCommand = <whatever you expect>;
MetaData expectedMetaData = <whatever you expect>;
// Code to construct your CommandModule with mockCommandBus.
// ACT
// Code to invoke the method being tested.
// ASSERT
Assert.AreEqual(expectedCommand, mockCommandBus.PassedCommand);
Assert.AreEqual(expectedMetaData , mockCommandBus.PassedMetaData );
}
Caveat:
Note that this is only one approach to unit testing that happens to fit exactly what you are asking for here. Excessive use of mocks to test explicit interaction with dependencies at a low level can lead to the development of very brittle test suites that are testing an underlying implementation rather than behaviour of a system.

Unit Testing with dependencies that have constructors

I need to some how unit test this method. The problem is that FsFileGroupFile is not easily mocked, it has complex constructor requirements and doesn't directly use an interface. _blockReaderFactory on the other hand is an interface and therefore easy to mock. How can I mock such a complicated object. I'm using Rhino Mocks and the Microsoft Unit Testing Framework. Any one have any ideas?
public void ReadGeneral(FsFileGroupFile a_file, FileItemData a_fileItemData)
{
try
{
var blockReader = _blockReaderFactory.Create(a_file.File.FullName, "CabinetData/StartData");
var version = blockReader.ReadVersion();
var name = blockReader.ReadString();
var type = blockReader.ReadString();
var defaultHeight = blockReader.ReadDouble();
var defaultWidth = blockReader.ReadDouble();
var defaultDepth = blockReader.ReadDouble();
a_fileItemData.Name = name;
a_fileItemData.DefaultWidth = defaultWidth * 100.0;
a_fileItemData.DefaultHeight = defaultHeight * 100.0;
a_fileItemData.DefaultDepth = defaultDepth * 100.0;
}
catch (Exception ex)
{
throw new IOException("General data could not be read from block data.", ex);
}
}
It seems that you're only using a_file to get the filename. So why not create an interface FilenameSupplier (or similar), and write a wrapper that implements it?
Java code example (added before question was tagged as C#...):
interface FilenameSupplier {
String getName();
}
public void ReadGeneral(FilenameSupplier a_file, FileItemData a_fileItemData) {
...
a_file.getName();
...
}
class ConcreteSupplier implements FilenameSupplier {
private final FsFileGroupFile file;
public ConcreteSupplier(FsFileGroupFile file) { this.file = file; }
String getName() { return a_file.File.FullName; }
}
You should extract some interface from FsFileGroupFile and pass it into constructor argument.
Then you can easily mock this interface with your preferable framework, Rhino Mocks in your case.
If it is not appropriate, you should build your FsFileGroupFile and may be use mocks when passing arguments in its complex constructor.
Seems that there is no another options, except may be you should review your design here. If classes are so hard to test it can be a sign of poor design.
When I have had to create complicated objects in a test I've used the Test Data Builder Pattern. As an example let's assume that you have five values to pass to the constructor:
public FsFileGroupFile(string firstProperty, string secondProperty,
string thirdProperty, string fourthProperty, string fifthProperty)
{
// constructor logic goes here
}
This would then be wrapped with a test builder class in the unit test project:
public class FsFileGroupFileBuilder
{
public string FirstProperty { get; set; }
public string SecondProperty { get; set; }
public string ThirdProperty { get; set; }
public string FourthProperty { get; set; }
public string FifthProperty { get; set; }
public FsFileGroupFile Build()
{
return new FsFileGroupFile(FirstProperty, SecondProperty, ThirdProperty,
FourthProperty, FifthProperty);
}
}
Now you can assign values to only the properties you care about and build your object in this way:
// in your test setup use this to initial to a default/valid state
var fsFileGroupBuilder = new fsFileGroupBuilder
{
FirstProperty = "Default",
SecondProperty = "Default",
ThirdProperty = "Default",
FourthProperty = "Default",
FifthProperty = "Default"
}
Note: Rhino Mocks can probably set those default value for you, but I have not used it personally so I'm not sure.
// Override the properties in each test
fsFileGroupBuilder.ThirdProperty = "Value needed for unit test."
// create
var fileItemData = new FileItemData();
ReadGeneral(fsFileGroupBuilder.Build(), fileItemData);
There are other open source libraries that can help with generating the test data such as NBuilder which have worked well for me in the past.
The main point here is that the complex constructor can be abstracted away with a builder which will allow you to concentrate on testing your business logic instead of satisfying the constructor in every test.

Categories

Resources