Unit testing of complex objects C# - c#

I wrote a short application, but I ran into the problem of writing a unit test Method MaximumRowSum_DefectiveLines. Please tell me how I should act, my class for testing
public class OutputtingStrings
{
public class MaxSumLineResult
{
public int MaxSumLineIndex { get; set; }
public List<string> DefectiveLines { get; set; }
public override string ToString()
{
return $"Line number with maximum sum of elements: { MaxSumLineIndex + 1}"; /* + "\n" +
$"Defective lines:{string.Join("\n", DefectiveLines)}";*/
}
}
public static bool IsValidateFileExist(string filePath)
{
if (File.Exists(filePath))
{
return true;
}
else
{
return false;
}
}
public MaxSumLineResult MaximumRowSum_DefectiveLines(string[] fileData)
{
List<string> defectiveLines = new List<string>();
int lineNumber = 0;
var indexOfLines = new Dictionary<int, double>();
foreach (var line in fileData)
{
NumberStyles style = NumberStyles.Number;
CultureInfo culture = CultureInfo.CreateSpecificCulture("en-GB");
var stringElements = line.Split(",", StringSplitOptions.RemoveEmptyEntries);
if (stringElements.Any(n => double.TryParse(n, style, culture, out var number)))
{
indexOfLines.Add(lineNumber, stringElements.Sum(n =>
{
return double.Parse(n, style, culture);
}));
}
else
{
defectiveLines.Add(line);
}
lineNumber++;
}
var maxSumLineIndex = indexOfLines.FirstOrDefault(x =>
x.Value == indexOfLines.Values.Max()).Key;
var resultLines = new MaxSumLineResult
{
MaxSumLineIndex = maxSumLineIndex,
DefectiveLines = defectiveLines
};
return resultLines;
}
}
My unit testing class:
[TestClass]
public class UnitTestOutputtingStrings
{
[TestMethod]
public void Should_FindingMaximumRowSum_TheFileIsValidAndReadable()
{
/* Arrange*/
var maxsumlineresult = new MaxSumLineResult();
var sut = new OutputtingStrings();
/* Act*/
/* Assert*/
}
}
I have read the book "The Art of Unit Testing. With Examples in C#". I understand the principles, but I do not know how to work with complex classes. Thank you guys in advance, I will be glad to every answer or link to a source with materials on unit testing.

For sure in the method, there is too much responsibility.
I think that the good idea to start is to divide the method into more than one smaller methods. After that unit testing of that method would be simpler to be done.

Related

How to struct an object to represent a list of topics?

I'm coding at C# and I'm trying to make an OOP representation of a list of topics. I tried countless approaches but I still not being able to reach the desired result.
I want to make a method later that will output it like:
1) Text
1.1) Text
2) Text
2.1) Text
2.2) Text
2.2.1) Text
2.2.2) Text
2.3) Text
3) Text
3.1) Text
When needed to get a single topic, I would like to create a method calling my object like:
private string GetSingleTopic()
{
return $"{Topic.Numerator}) {Topic.Text}"
}
EXAMPLES
Example 1
I would be able to instantiate the object such as:
var variable = new TopicObject
{
"TitleA",
"TitleB",
"TitleC"
}
/* --- OUTPUT ---
1) TitleA
2) TitleB
3) TitleC
--- OUTPUT --- */
Example 2
Be able to instantiate the object such as:
var variable = new TopicObject
{
"TitleA",
"TitleB",
"TitleC":
{
"TitleD":
{
"TitleE"
},
"TitleF":
{
"TitleG",
"TitleH"
}
}
}
/* --- OUTPUT ---
1) TitleA
2) TitleB
3) TitleC
3.1) TitleD
3.1.2) TitleE
3.2) TitleF
3.2.1) TitleG
3.2.2) TitleH
--- OUTPUT --- */
My Approach
This, was one of my many approaches. I couldn't use it because I can't initialize the inner topic List in the way i mentioned, like an hierarchy.
But the structure is pretty similar to what I want to achieve so I decided to put here as an example.
public abstract class TopicBase
{
public List<Topic> Topics { get; set; } // optional
protected TopicBase() { Topics = new List<Topic>(); }
protected TopicBase(List<Topic> topics) { Topics = topics; }
public TopicBase AddTopic(string topicText)
{
var test = new Topic(topicText);
Topics.Add(test);
return this;
}
}
public class Topic
{
public Topic(string text)
{
Numerator++;
Text = text;
}
public int Numerator { get; }
public string Text { get; }
}
public class TopicLevel1 : TopicBase { }
public class TopicLevel2 : TopicBase { }
public class TopicLevel3 : TopicBase { }
Let's start by defining a data structure that can hold the topics:
public class Topics<T> : List<Topic<T>> { }
public class Topic<T> : List<Topic<T>>
{
public T Value { get; private set; }
public Topic(T value, params Topic<T>[] children)
{
this.Value = value;
if (children != null)
this.AddRange(children);
}
}
That allows us to write this code:
var topics = new Topics<string>()
{
new Topic<string>("TitleA"),
new Topic<string>("TitleB"),
new Topic<string>("TitleC",
new Topic<string>("TitleD",
new Topic<string>("TitleE")),
new Topic<string>("TitleF",
new Topic<string>("TitleF"),
new Topic<string>("TitleH")))
};
That matches your "Example 2" data.
To output the result we add two ToOutput methods.
To Topics<T>:
public IEnumerable<string> ToOutput(Func<T, string> format)
=> this.SelectMany((t, n) => t.ToOutput(0, $"{n + 1}", format));
To Topic<T>:
public IEnumerable<string> ToOutput(int depth, string prefix, Func<T, string> format)
{
yield return $"{new string(' ', depth)}{prefix}) {format(this.Value)}";
foreach (var child in this.SelectMany((t, n) => t.ToOutput(depth + 1, $"{prefix}.{n + 1}", format)))
{
yield return child;
}
}
Now I can run this code:
foreach (var line in topics.ToOutput(x => x))
{
Console.WriteLine(line);
}
That gives me:
1) TitleA
2) TitleB
3) TitleC
3.1) TitleD
3.1.1) TitleE
3.2) TitleF
3.2.1) TitleF
3.2.2) TitleH
If the goal is to have some structure that will help with the output of the topic hierarchy, you already have it (and may even be able to simplify it more).
For example, here's an almost-minimal Topic to get what you want:
public class Topic
{
public string Title { get; set; }
public List<Topic> SubTopics { get; private set; } = new();
public Topic() : this("DocRoot") { }
public Topic(string title) => Title = title;
public void AddTopics(List<Topic> subTopics) => SubTopics.AddRange(subTopics);
public void AddTopics(params Topic[] subTopics) => SubTopics.AddRange(subTopics);
public override string ToString() => Title;
}
That is, you have a Topic that can have SubTopics (aka children) and that's all you need.
With that, we can build your second example:
var firstLevelTopics = new List<Topic>();
for (var c = 'A'; c < 'D'; ++c)
{
firstLevelTopics.Add(new Topic(c.ToString()));
}
var cTopic = firstLevelTopics.Last();
cTopic.AddTopics(
new Topic
{
Title = "D",
SubTopics = { new Topic("E") }
},
new Topic
{
Title = "F",
SubTopics = { new Topic("G"), new Topic("H") }
});
Now, imagine if we had a function to print the hierarchy from the list of top-level topics. I'm leaving the final detail for yourself in case this is homework.
PrintTopics(firstLevelTopics);
static void PrintTopics(List<Topic> topics, string prefix = "")
{
// For the simple case, we can just loop and print...
for (var i = 0; i < topics.Count; ++i)
{
var topic = topics[i];
var level = i + 1;
Console.WriteLine($"{prefix}{level}) {topic}");
// ...but, if we want to print the children, we need more.
// Make a recursive call to print the SubTopics
// PrintTopics(<What goes here?>);
}
}

XUnit InlineData with Objects? [duplicate]

Xunit has a nice feature: you can create one test with a Theory attribute and put data in InlineData attributes, and xUnit will generate many tests, and test them all.
I want to have something like this, but the parameters to my method are not 'simple data' (like string, int, double), but a list of my class:
public static void WriteReportsToMemoryStream(
IEnumerable<MyCustomClass> listReport,
MemoryStream ms,
StreamWriter writer) { ... }
There are many xxxxData attributes in XUnit. Check out for example the MemberData attribute.
You can implement a property that returns IEnumerable<object[]>. Each object[] that this method generates will be then "unpacked" as a parameters for a single call to your [Theory] method.
See i.e. these examples from here
Here are some examples, just for a quick glance.
MemberData Example: just here at hand
public class StringTests2
{
[Theory, MemberData(nameof(SplitCountData))]
public void SplitCount(string input, int expectedCount)
{
var actualCount = input.Split(' ').Count();
Assert.Equal(expectedCount, actualCount);
}
public static IEnumerable<object[]> SplitCountData =>
new List<object[]>
{
new object[] { "xUnit", 1 },
new object[] { "is fun", 2 },
new object[] { "to test with", 3 }
};
}
XUnit < 2.0: Another option is ClassData, which works the same, but allows to easily share the 'generators' between tests in different classes/namespaces, and also separates the 'data generators' from the actual test methods.
ClassData Example
public class StringTests3
{
[Theory, ClassData(typeof(IndexOfData))]
public void IndexOf(string input, char letter, int expected)
{
var actual = input.IndexOf(letter);
Assert.Equal(expected, actual);
}
}
public class IndexOfData : IEnumerable<object[]>
{
private readonly List<object[]> _data = new List<object[]>
{
new object[] { "hello world", 'w', 6 },
new object[] { "goodnight moon", 'w', -1 }
};
public IEnumerator<object[]> GetEnumerator()
{ return _data.GetEnumerator(); }
IEnumerator IEnumerable.GetEnumerator()
{ return GetEnumerator(); }
}
XUnit >= 2.0: Instead of ClassData, now there's an 'overload' of [MemberData] that allows to use static members from other classes. Examples below have been updated to use it, since XUnit < 2.x is pretty ancient now.
Another option is ClassData, which works the same, but allows to easily share the 'generators' between tests in different classes/namespaces, and also separates the 'data generators' from the actual test methods.
MemberData Example: look there to another type
public class StringTests3
{
[Theory, MemberData(nameof(IndexOfData.SplitCountData), MemberType = typeof(IndexOfData))]
public void IndexOf(string input, char letter, int expected)
{
var actual = input.IndexOf(letter);
Assert.Equal(expected, actual);
}
}
public class IndexOfData : IEnumerable<object[]>
{
public static IEnumerable<object[]> SplitCountData =>
new List<object[]>
{
new object[] { "hello world", 'w', 6 },
new object[] { "goodnight moon", 'w', -1 }
};
}
Disclaimer :)
Last time checked #20210903 with dotnetfiddle.net on C# 5.0 and xunit 2.4.1 .. and failed. I couldn't mix-in a test-runner into that fiddle. But at least it compiled fine. Note that this was originally written years ago, things changed a little. I fixed them according to my hunch and comments. So.. it may contain inobvious typos, otherwise obvious bugs that would instantly pop up at runtime, and traces of milk & nuts.
Suppose that we have a complex Car class that has a Manufacturer class:
public class Car
{
public int Id { get; set; }
public long Price { get; set; }
public Manufacturer Manufacturer { get; set; }
}
public class Manufacturer
{
public string Name { get; set; }
public string Country { get; set; }
}
We're going to fill and pass the Car class to a Theory test.
So create a 'CarClassData' class that returns an instance of the Car class like below:
public class CarClassData : IEnumerable<object[]>
{
public IEnumerator<object[]> GetEnumerator()
{
yield return new object[] {
new Car
{
Id=1,
Price=36000000,
Manufacturer = new Manufacturer
{
Country="country",
Name="name"
}
}
};
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
It's time for creating a test method(CarTest) and define the car as a parameter:
[Theory]
[ClassData(typeof(CarClassData))]
public void CarTest(Car car)
{
var output = car;
var result = _myRepository.BuyCar(car);
}
**If you're going to pass a list of car objects to Theory then change the CarClassData as follow:
public class CarClassData : IEnumerable<object[]>
{
public IEnumerator<object[]> GetEnumerator()
{
yield return new object[] {
new List<Car>()
{
new Car
{
Id=1,
Price=36000000,
Manufacturer = new Manufacturer
{
Country="Iran",
Name="arya"
}
},
new Car
{
Id=2,
Price=45000,
Manufacturer = new Manufacturer
{
Country="Torbat",
Name="kurosh"
}
}
}
};
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
And the theory will be:
[Theory]
[ClassData(typeof(CarClassData))]
public void CarTest(List<Car> cars)
{
var output = cars;
}
Good Luck
To update #Quetzalcoatl's answer: The attribute [PropertyData] has been superseded by [MemberData] which takes as argument the string name of any static method, field, or property that returns an IEnumerable<object[]>. (I find it particularly nice to have an iterator method that can actually calculate test cases one at a time, yielding them up as they're computed.)
Each element in the sequence returned by the enumerator is an object[] and each array must be the same length and that length must be the number of arguments to your test case (annotated with the attribute [MemberData] and each element must have the same type as the corresponding method parameter. (Or maybe they can be convertible types, I don't know.)
(See release notes for xUnit.net March 2014 and the actual patch with example code.)
Creating anonymous object arrays is not the easiest way to construct the data so I used this pattern in my project.
First define some reusable, shared classes:
//http://stackoverflow.com/questions/22093843
public interface ITheoryDatum
{
object[] ToParameterArray();
}
public abstract class TheoryDatum : ITheoryDatum
{
public abstract object[] ToParameterArray();
public static ITheoryDatum Factory<TSystemUnderTest, TExpectedOutput>(TSystemUnderTest sut, TExpectedOutput expectedOutput, string description)
{
var datum= new TheoryDatum<TSystemUnderTest, TExpectedOutput>();
datum.SystemUnderTest = sut;
datum.Description = description;
datum.ExpectedOutput = expectedOutput;
return datum;
}
}
public class TheoryDatum<TSystemUnderTest, TExpectedOutput> : TheoryDatum
{
public TSystemUnderTest SystemUnderTest { get; set; }
public string Description { get; set; }
public TExpectedOutput ExpectedOutput { get; set; }
public override object[] ToParameterArray()
{
var output = new object[3];
output[0] = SystemUnderTest;
output[1] = ExpectedOutput;
output[2] = Description;
return output;
}
}
Now your individual test and member data is easier to write and cleaner...
public class IngredientTests : TestBase
{
[Theory]
[MemberData(nameof(IsValidData))]
public void IsValid(Ingredient ingredient, bool expectedResult, string testDescription)
{
Assert.True(ingredient.IsValid == expectedResult, testDescription);
}
public static IEnumerable<object[]> IsValidData
{
get
{
var food = new Food();
var quantity = new Quantity();
var data= new List<ITheoryDatum>();
data.Add(TheoryDatum.Factory(new Ingredient { Food = food } , false, "Quantity missing"));
data.Add(TheoryDatum.Factory(new Ingredient { Quantity = quantity } , false, "Food missing"));
data.Add(TheoryDatum.Factory(new Ingredient { Quantity = quantity, Food = food } , true, "Valid" ));
return data.ConvertAll(d => d.ToParameterArray());
}
}
}
The string Description property is to throw yourself a bone when one of your many test cases fail.
You can try this way:
public class TestClass {
bool isSaturday(DateTime dt)
{
string day = dt.DayOfWeek.ToString();
return (day == "Saturday");
}
[Theory]
[MemberData("IsSaturdayIndex", MemberType = typeof(TestCase))]
public void test(int i)
{
// parse test case
var input = TestCase.IsSaturdayTestCase[i];
DateTime dt = (DateTime)input[0];
bool expected = (bool)input[1];
// test
bool result = isSaturday(dt);
result.Should().Be(expected);
}
}
Create another class to hold the test data:
public class TestCase
{
public static readonly List<object[]> IsSaturdayTestCase = new List<object[]>
{
new object[]{new DateTime(2016,1,23),true},
new object[]{new DateTime(2016,1,24),false}
};
public static IEnumerable<object[]> IsSaturdayIndex
{
get
{
List<object[]> tmp = new List<object[]>();
for (int i = 0; i < IsSaturdayTestCase.Count; i++)
tmp.Add(new object[] { i });
return tmp;
}
}
}
For my needs I just wanted to run a series of 'test users' through some tests - but [ClassData] etc. seemed overkill for what I needed (because the list of items was localized to each test).
So I did the following, with an array inside the test - indexed from the outside:
[Theory]
[InlineData(0)]
[InlineData(1)]
[InlineData(2)]
[InlineData(3)]
public async Task Account_ExistingUser_CorrectPassword(int userIndex)
{
// DIFFERENT INPUT DATA (static fake users on class)
var user = new[]
{
EXISTING_USER_NO_MAPPING,
EXISTING_USER_MAPPING_TO_DIFFERENT_EXISTING_USER,
EXISTING_USER_MAPPING_TO_SAME_USER,
NEW_USER
} [userIndex];
var response = await Analyze(new CreateOrLoginMsgIn
{
Username = user.Username,
Password = user.Password
});
// expected result (using ExpectedObjects)
new CreateOrLoginResult
{
AccessGrantedTo = user.Username
}.ToExpectedObject().ShouldEqual(response);
}
This achieved my goal, while keeping the intent of the test clear. You just need to keep the indexes in sync but that's all.
Looks nice in the results, it's collapsable and you can rerun a specific instance if you get an error:
This is how I solved your problem, I had the same scenario. So inline with custom objects and a different number of objects on each run.
[Theory]
[ClassData(typeof(DeviceTelemetryTestData))]
public async Task ProcessDeviceTelemetries_TypicalDeserialization_NoErrorAsync(params DeviceTelemetry[] expected)
{
// Arrange
var timeStamp = DateTimeOffset.UtcNow;
mockInflux.Setup(x => x.ExportTelemetryToDb(It.IsAny<List<DeviceTelemetry>>())).ReturnsAsync("Success");
// Act
var actual = await MessageProcessingTelemetry.ProcessTelemetry(JsonConvert.SerializeObject(expected), mockInflux.Object);
// Assert
mockInflux.Verify(x => x.ExportTelemetryToDb(It.IsAny<List<DeviceTelemetry>>()), Times.Once);
Assert.Equal("Success", actual);
}
So this is my unit test, notice the params parameter. This allow to send a different number of object. And now my DeviceTelemetryTestData class :
public class DeviceTelemetryTestData : IEnumerable<object[]>
{
public IEnumerator<object[]> GetEnumerator()
{
yield return new object[] { new DeviceTelemetry { DeviceId = "asd" }, new DeviceTelemetry { DeviceId = "qwe" } };
yield return new object[] { new DeviceTelemetry { DeviceId = "asd" }, new DeviceTelemetry { DeviceId = "qwe" } };
yield return new object[] { new DeviceTelemetry { DeviceId = "asd" }, new DeviceTelemetry { DeviceId = "qwe" } };
yield return new object[] { new DeviceTelemetry { DeviceId = "asd" }, new DeviceTelemetry { DeviceId = "qwe" } };
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
Hope it helps !
Despite this has already been answered I just want to add an improvement here.
The restriction of passing objects in InlineData attribute is not a limitiation of xUnit itself but C# attributes.
See this compiler error: Compiler Error CS0182
xUnit.Sdk provides you with DataAttribute class that you could inherit and override its GetData method and use it to pass whatever you feel like you want..
I usually use it alongside DataTestBuilders pattern and build something like that..
public class ValidComplexObjectDataSource : DataAttribute
{
public override IEnumerable<object[]> GetData(MethodInfo testMethod)
{
yield return new object[] {
ComplexObjectBuilder
.BasicComplexObject()
.Build()
};
yield return new object[] {
ComplexObjectBuilder
.BasicComplexObject()
.WithoutSomeAttribute()
.Build()
};
// ... list all test cases you want to pass to your method
}
}
This ComplexObjectBuilder could be whatever your object is, highly recommend checking builder pattern
[Theory]
[Trait("Validation", "CreateXYZCommand")]
[ValidComplexObjectDataSource]
public void CreateXYZCommandValidator_WithValidInput_ShouldPassAllValidations(CreateComplexObjectInput createComplexObjectInput)
{
var command = new CreateXYZCommand(createComplexObjectInput);
var result = _validator.TestValidate(command);
result.ShouldNotHaveAnyValidationErrors();
}
I only demonstrated it with a single object, you have an array of objects you can yield.
yield return new object[] {
ComplexObject_1,
ComplexObject_2,
string_attribute,
int_attribute
};
and have these as arguments to your test cases.
You can utilize TheoryData for complex types like classes.
[Theory, MemberData(nameof(CustomClassTests))]
public async Task myTestName(MyCustomClass customClassTestData) { ... }
public record MyCustomClass { ... }
public static TheoryData<MyCustomClass> CustomClassTests {
get {
return new() {
new MyCustomClass{ ... },
new MyCustomClass{ ... },
...
};
}
}
I guess you mistaken here. What xUnit Theory attribute actually means: You want to test this function by sending special/random values as parameters that this function-under-test receives. That means that what you define as the next attribute, such as: InlineData, PropertyData, ClassData, etc.. will be the source for those parameters. That means that you should construct the source object to provide those parameters. In your case I guess you should use ClassData object as source. Also - please note that ClassData inherits from: IEnumerable<> - that means each time another set of generated parameters will be used as incoming parameters for function-under-test until IEnumerable<> produces values.
Example here: Tom DuPont .NET
Example may be incorrect - I didn't use xUnit for a long time

Is there a simpler way to return fields from static function?

I often want to parse a string into various bits and have a readable way to return them.
I like this approach, but it involves creating a specific class
long orderID = Utils.UnTradeIdent(tradeIdent).OrderID;
In Utils.cs:
public class TradeIdentData
{
public string AccountIdent;
public long OrderID;
public string SubID;
}
public static TradeIdentData UnTradeIdent(string tradeIdent)
{
TradeIdentData tradeIdentData = new TradeIdentData();
var parts = tradeIdent.Split('!');
tradeIdentData.AccountIdent = parts[0];
if (parts[1].Contains("."))
{
var bits = parts[1].Split('.');
tradeIdentData.OrderID = long.Parse(bits[1]);
tradeIdentData.SubID = bits[1];
}
else
{
tradeIdentData.OrderID = long.Parse(parts[1]);
tradeIdentData.SubID = "";
}
return tradeIdentData;
}
A separate class with well-named properties (which you are already using) is currently the most readable way of doing this.
In C# 7 you will be able to use tuples for return values, like so:
public static (string AccountIdent, string OrderID, string SubID) UnTradeIdent(string tradeIdent)
{
string accountIdent, orderID, subID ;
... Code to initialise accountIdent, orderID and subID appropriately ...
// Now return the data as a tuple:
return (accountIdent, orderID, subID);
}
You can consume this as follows:
long orderID = Utils.UnTradeIdent(tradeIdent).OrderID;
Or if you want all the values:
var result = Utils.UnTradeIdent(tradeIdent);
// Use result.OrderId, result.SubID or result.AccountIdent
This is not going to be available until some time next year, though.
Also, even though this new tuple support makes it more convenient to WRITE the code, it doesn't let you document it using XML comments as well. Spending the time to write a simple and well-documented class will still often be better than using the new C# 7 tuple support.
See here for more details.
You can also use the out keyword to pass arguments by reference, see MSDN article out (C# Reference):
public static void UnTradeIdent(string tradeIdent, out string AccountIdent, out long OrderID, out string SubID)
{
var parts = tradeIdent.Split('!');
AccountIdent = parts[0];
if (parts[1].Contains("."))
{
var bits = parts[1].Split('.');
OrderID = long.Parse(bits[1]);
SubID = bits[1];
}
else
{
OrderID = long.Parse(parts[1]);
SubID = "";
}
}
UPDATED with suggestion from comments:
public static bool UnTradeIdent(string tradeIdent, out string AccountIdent, out long OrderID, out string SubID)
{
bool result = false;
AccountIdent = "";
OrderID = 0;
SubID = "";
try
{
var parts = tradeIdent.Split('!');
AccountIdent = parts[0];
if (parts[1].Contains("."))
{
var bits = parts[1].Split('.');
OrderID = long.Parse(bits[1]);
SubID = bits[1];
}
else
{
OrderID = long.Parse(parts[1]);
SubID = "";
}
}
catch(ArgumentNullException ane)
{
// Handle parsing exception
}
catch (FormatException fe)
{
// Handle parsing exception
}
catch (OverflowException oe)
{
// Handle parsing exception
}
return result;
}
Its pretty simple to do just by changing the return type to dynamic and using an anonymous class
public static dynamic UnTradeIdent(string tradeIdent)
{
var value1 = //parselogic
var value2 = //parselogic
return new { Identity = value1, Item2 = value2};
}
I would consider making additional static methods. Your current implementation is cleaner when you require all of the returned properties, but something like below might be appropriate when you only need one of them.
public static string TradeIdentToAccountIdent(string tradeIdent)
{
var parts = tradeIdent.Split('!');
return parts[0];
}
public static long TradeIdentToOrderID(string tradeIdent)
{
var parts = tradeIdent.Split('!');
if (parts[1].Contains("."))
{
var bits = parts[1].Split('.');
return long.Parse(bits[1]); // Taken from your example, should probably be bits[0]?
}
else
return long.Parse(parts[1]);
}
// My own take on it this time, you could obviously use your logic as well.
public static string TradeIdentToSubID(string tradeIdent)
{
var order = tradeIdent.Split('!')[1];
if (order.Contains("."))
return order.Split('.')[1];
else
return String.Empty;
}

Mock method in Parallel.ForEach always returns null

I have the following code:
public int LoadFilesAndSaveInDatabase(string filesPath)
{
var calls = new ConcurrentStack<GdsCallDto>();
var filesInDirectory = this._directoryProxy.GetFiles(filesPath);
if (filesInDirectory.Any())
{
Parallel.ForEach(filesInDirectory, file =>
{
var lines = this._fileProxy.ReadAllLines(file, Encoding.Unicode);
if (lines.Any())
{
// Reads the file and setup a new DTO.
var deserializedCall = this._fileManager.DeserializeFileContent(lines, Path.GetFileName(file));
// Insert the DTO in the database.
this._gdsCallsData.InsertOrUpdateGdsCall(deserializedCall);
// We keep track of the dto to count the number of restored items.
calls.Push(deserializedCall);
}
});
}
return calls.Count;
}
And I have the following unit test:
[TestMethod]
public void ShouldLoadFilesAndSaveInDatabase()
{
// Arrange
var path = RandomGenerator.GetRandomString(56);
var encoding = Encoding.Unicode;
var fileNameEnvironment = RandomGenerator.GetRandomString();
var fileNameModule = RandomGenerator.GetRandomString();
var fileNameRecordLocator = RandomGenerator.GetRandomString(6);
var fileNameTimestamp = RandomGenerator.GetRandomDateTime().ToString("O").Replace(':', 'o');
// We simulate the presence of 4 files.
var files = new List<string>
{
RandomGenerator.GetRandomString(255),
RandomGenerator.GetRandomString(255),
RandomGenerator.GetRandomString(255),
RandomGenerator.GetRandomString(255)
}.ToArray();
var expectedResult = 4;
this._directoryProxy.Expect(d => d.GetFiles(path))
.Return(files);
this._fileProxy.Expect(f => f.ReadAllLines(path, encoding))
.Return(files).Repeat.Times(files.Length);
// Act
var result = this._databaseReloadManager.LoadFilesAndSaveInDatabase(path);
// Assert
Assert.AreEqual(result, expectedResult);
this._directoryProxy.AssertWasCalled(d => d.GetFiles(path));
this._fileProxy.AssertWasCalled(f => f.ReadAllLines(path, Encoding.Unicode));
}
The problem is on the following line:
var lines = this._fileProxy.ReadAllLines(file, Encoding.Unicode);
Even though I set an expectation and a return value, when I run the unit test, it always returns null.
I am using Rhino.Mocks, it works perfectly fine elsewhere but not there.
I had a look at some discussions here but none of them helped. Can it be due to the use of Parallel.ForEach? Is there a way of doing such a mock?
If you need any other info, please let me know.
I don't think there is a problem with the Parallelization. It seems your problem is related to the proxy instance setup with Rhino Mock.
Ensure what you pass into the parameters of the ReadAllLines are the same as you call them when it run through the production code.
this._fileProxy.Expect(f => f.ReadAllLines(path, encoding))
.Return(files).Repeat.Times(files.Length);
For instance if you setup on different path and the value of that path diefferent when test executes you may see NULL in return. But again hard to tell without seeing the full setup/constructor in the code. Also check the random generators see what has been used in each time.
The below is I sort of put together and working for me.
Working means I don't get NULL for:
var lines = this._fileProxy.ReadAllLines(file, Encoding.Unicode);
//some dummy code so I can compile
public interface IProxyDir
{
IEnumerable<string> GetFiles(string path);
}
public class GdsCallDto
{
}
public class Proxy : IProxyDir
{
public IEnumerable<string> GetFiles(string path)
{
throw new NotImplementedException();
}
}
public interface IFileDir
{
IEnumerable<string> ReadAllLines(string path, Encoding encoding);
}
public class FileProxy : IFileDir
{
public IEnumerable<string> ReadAllLines(string path, Encoding encoding)
{
throw new NotImplementedException();
}
}
public interface IFileMgr
{
string DeserializeFileContent(IEnumerable<string> lines, string content);
}
public class FileMgr : IFileMgr
{
public string DeserializeFileContent(IEnumerable<string> lines, string content)
{
throw new NotImplementedException();
}
}
//system under test
public class Sut
{
private IProxyDir _directoryProxy;
private IFileDir _fileProxy;
private IFileMgr _fileManager;
public Sut(IProxyDir proxyDir, IFileDir fileProxy, IFileMgr mgr)
{
_fileManager = mgr;
_directoryProxy = proxyDir;
_fileProxy = fileProxy;
}
public int LoadFilesAndSaveInDatabase(string filesPath)
{
var calls = new ConcurrentStack<GdsCallDto>();
var filesInDirectory = this._directoryProxy.GetFiles(filesPath);
if (filesInDirectory.Any())
{
Parallel.ForEach(filesInDirectory, file =>
{
var lines = this._fileProxy.ReadAllLines("ssss", Encoding.Unicode);
if (lines.Any())
{
// Reads the file and setup a new DTO.
var deserializedCall = this._fileManager.DeserializeFileContent(lines, Path.GetFileName("file"));
// Insert the DTO in the database.
//this._gdsCallsData.InsertOrUpdateGdsCall(deserializedCall);
// We keep track of the dto to count the number of restored items.
//calls.Push(deserializedCall);
}
});
}
return 1;
}
}
Sample Unit Test
[TestClass]
public class UnitTest1
{
private IProxyDir _directoryProxy;
private IFileDir _fileProxy;
private IFileMgr _fileMgr;
private Sut _sut;
public UnitTest1()
{
_directoryProxy = MockRepository.GenerateMock<IProxyDir>();
_fileProxy = MockRepository.GenerateMock<IFileDir>();
_fileMgr = MockRepository.GenerateMock<IFileMgr>();
}
[TestMethod]
public void ShouldLoadFilesAndSaveInDatabase()
{
// Arrange
var path = RandomGenerator.GetRandomString(56);
var encoding = Encoding.Unicode;
var fileNameEnvironment = RandomGenerator.GetRandomString(5);
var fileNameModule = RandomGenerator.GetRandomString(5);
var fileNameRecordLocator = RandomGenerator.GetRandomString(6);
var fileNameTimestamp = RandomGenerator.GetRandomDateTime().ToString("O").Replace(':', 'o');
// We simulate the presence of 4 files.
var files = new List<string>
{
RandomGenerator.GetRandomString(255),
RandomGenerator.GetRandomString(255),
RandomGenerator.GetRandomString(255),
RandomGenerator.GetRandomString(255)
}.ToArray();
var expectedResult = 4;
this._directoryProxy.Expect(d => d.GetFiles(path))
.Return(files);
this._fileProxy.Expect(f => f.ReadAllLines(path, encoding))
.Return(files).Repeat.Times(files.Length);
_sut = new Sut(_directoryProxy, _fileProxy, _fileMgr);
// Act
var result = this._sut.LoadFilesAndSaveInDatabase(path);
// Assert
Assert.AreEqual(result, expectedResult);
this._directoryProxy.AssertWasCalled(d => d.GetFiles(path));
this._fileProxy.AssertWasCalled(f => f.ReadAllLines(path, Encoding.Unicode));
}
}
internal class RandomGenerator
{
public static string GetRandomString(int number)
{
return "ssss";
}
public static DateTime GetRandomDateTime()
{
return new DateTime();
}
}
I could get rid of this issue, probably caused by the use of random values. I am now calling the method IgnoreArguments() on my expectation:
this._fileProxy.Expect(f => f.ReadAllLines(path, encoding))
.Return(files).Repeat.Times(files.Length).IgnoreArguments();
It does the trick (i.e. the unit test is running successfully), but I do not know if it is very elegant.

How do I get a distinct value of items in a list of object or structure?

I have a List. This collection holds an object containing the properties of a class.
I want a distinct value of list with respect to any specific property of a class. I have attached some sample code; please check & let me know if you guys have any solutions:
class Test
{
public string firstname{get;set;}
public string lastname{get;set;}
}
class Usetheaboveclass
{
Test objTest=new Test();
List<Test> lstTest=new List<Test>();
objTest.firstname="test";
objTest.lastname="testing";
//Now i want a distinct value with respect to lastname.if i use
lstTest=lstTest.Distinct().Tolist();
//It will process according to all properties.
}
Can you suggest me a way to do this?
Try this approach.
var distinct = lstTest.GroupBy(item => item.lastname).Select(item => item.First()).ToList();
If you only need to do this for one property, override the Equals and GetHashCode methods in Test. These are what Distinct() uses to define duplicates.
If you need to do this for multiple properties, define an IEqualityComparer (the usage is documented in this MSDN article).
Or , you can implement a custom comparer
public class LastNameComparer : IEqualityComparer<Test>
{
public bool Equals(Test x, Test y)
{
if (x == null)
return y == null;
return x.lastname == y.lastname;
}
public int GetHashCode(Test obj)
{
if (obj == null)
return 0;
return obj.lastname.GetHashCode();
}
}
Then , use it like
lstTest = lstTest.Distinct(new LastNameComparer()).ToList();
You can use overloaded version of Distinct. Please see sample code below:
internal class Test
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
internal class LastNameComparer : IEqualityComparer<Test>
{
bool IEqualityComparer<Test>.Equals(Test x, Test y)
{
if (x.LastName == y.LastName)
return true;
return false;
}
int IEqualityComparer<Test>.GetHashCode(Test obj)
{
return 0; // hashcode...
}
}
private static void Main(string[] args)
{
Test objTest = new Test {FirstName = "Perry", LastName = "Joe"};
Test objTest1 = new Test {FirstName = "Prince", LastName = "Joe"};
Test objTest2 = new Test { FirstName = "Prince", LastName = "Jim" };
List<Test> lstTest = new List<Test> {objTest, objTest1, objTest2};
var distinct = lstTest.Distinct(new LastNameComparer()).ToList();
foreach (var test in distinct)
{
Console.WriteLine(test.LastName);
}
Console.Read();
}
Output of this will be:
Joe
Jim

Categories

Resources