I have a method IsValid:
public void IsValid(string applicationNumber)
{
if (!applicationNumber.Length.Equals(15))
{
throw new ApplicationException(string.Format("De lengte van de rubriek: aanvraagnummer [001.], met waarde {0}, is niet valide.", applicationNumber));
} else {
applicationNumberExpression = "qwerty123456789";
if (!applicationNumberExpression.IsMatch(applicationNumber))
{
throw new ApplicationException(string.Format("Het aanvraagnummer [001.] met waarde {0} is niet conform de voorgeschreven structuur.", applicationNumber));
}
}
}
I try to write a unit test case for isvalid, but i get some errors.
public void IsValidTestApplicationNumber()
{
var appno1 = new MFA.Convana.BusinessLayer.ObjectModel.ApplicationNumber();
MFA.Convana.BusinessLayer.ObjectModel.ApplicationNumber appno = new
MFA.Convana.BusinessLayer.ObjectStore.ApplicationNumber();
string applicationNumber = "qwerty123456789";
Assert.AreSame(appno.IsValid(applicationNumber);//error in thisline "no overload for method takes one argument"
}
Your primary mistake is attempting to assert on a function that returns void. This isn't possible.
You have two options:
a) Leave IsValid as returning void, and replace:
Assert.AreSame(appno.IsValid(applicationNumber);
with:
appno.IsValid(applicationNumber);
OR
b) Change IsValid to return a bool. To do this, change:
Assert.AreSame(appno.IsValid(applicationNumber);
to either:
Assert.IsTrue(appno.IsValid(applicationNumber));
(depending on what you want the test to do)
Also, change:
public void IsValid(string applicationNumber)
{
if (!applicationNumber.Length.Equals(15))
{
throw new ApplicationException(string.Format("De lengte van de rubriek: aanvraagnummer [001.], met waarde {0}, is niet valide.", applicationNumber));
} else {
applicationNumberExpression = "qwerty123456789";
if (!applicationNumberExpression.IsMatch(applicationNumber))
{
throw new ApplicationException(string.Format("Het aanvraagnummer [001.] met waarde {0} is niet conform de voorgeschreven structuur.", applicationNumber));
}
}
}
to:
public bool IsValid(string applicationNumber)
{
if (!applicationNumber.Length.Equals(15))
{
throw new ApplicationException(string.Format("De lengte van de rubriek: aanvraagnummer [001.], met waarde {0}, is niet valide.", applicationNumber));
} else {
applicationNumberExpression = "qwerty123456789";
if (!applicationNumberExpression.IsMatch(applicationNumber))
{
throw new ApplicationException(string.Format("Het aanvraagnummer [001.] met waarde {0} is niet conform de voorgeschreven structuur.", applicationNumber));
}
}
return true;
}
no overload for method takes one argument
Clearly error says everything ...
Assert.AreSame(appno.IsValid(applicationNumber), /*TO WHAT SHOULD IT BE COMPARED*/);
Assert.AreSame(appno.IsValid(applicationNumber), false);
EDIT :
Extending this answer to be more accurate and on topic.
You're trying to compare two values but using reference comparer ( Assert.AreSame ).
This can fail because the 2 references are not the same ( read about references here ).
What you should do is to compare the two values. To do this you have to use different assertion methods.
For your example you can use Assert.IsTrue if you expect your method to return true or Assert.IsFalse if your expected value is false:
bool result = meObj.IsValid("someString");
// let's say you're expecting false
Assert.IsFalse(result);
// but if you're expecting true then change IsFalse to IsTrue
Or you can use AreEqual which in your case will be Assert.AreEqual<bool> :
bool result = meObj.IsValid("someString");
bool expected = false;
Assert.AreEqual(expected, result);
[TestClass]
public class UnitTest_MailClient
{
[TestMethod]
public void IsValid_TestApplicationNumber()
{
MFA.Convana.BusinessLayer.ObjectModel.ApplicationNumber appno = new MFA.Convana.BusinessLayer.ObjectStore.ApplicationNumber();
String Input;
String exception;
String TestCase;
XMLHelper TestData = new XMLHelper();
TestCase = TestData.GetTestDataString("IsValid");
String[] arr = TestCase.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
if (arr.Length > 0 && TestCase.Length > 0)
{
for (int i = 0; i < arr.Length; i++)
{
Input = arr[i].Substring(0, arr[i].IndexOf(TestData.FieldDelimiter));
exception = arr[i].Substring(arr[i].IndexOf(TestData.FieldDelimiter) + 3);
try
{
appno.IsValid(Input);
Assert.IsTrue(true);
}
catch (Exception ex)
{
Assert.AreEqual(exception, ex.Message);
}
}
}
else
{
Assert.Inconclusive("Test Skipped as no test data");
}
}
Related
I am very perplexed by a piece of code I came across :
string s = "this is my dummy string, it could be anything";
if (s is null or "") { // ???
DoSomething();
}
I have never seen a string being tested in that manner.
I've always only seen this :
if(string.IsNullOrEmpty(s))
I've tried googling it but the keywords involved are too generic to find any relevant result.
So, what do you think? Is this a fancy new efficient way of testing strings, or is it just some quirky habit?
To have a good judgement about the performance.
I write these codes and run them separately.
The result is insightful
using System;
public class Program
{
public static void Main()
{
Console.WriteLine("Start");
string s = "this is my dummy string, it could be anything";
var d1 = DateTime.Now;
for(var i=0; i<1000000000;i++)
{
if(string.IsNullOrEmpty(s))
{
Console.WriteLine("Hello Again");
}
}
Console.WriteLine("Method1: " + (DateTime.Now - d1).TotalMilliseconds);
Console.WriteLine("End");
}
}
using System;
public class Program
{
public static void Main()
{
Console.WriteLine("Start");
string s = "this is my dummy string, it could be anything";
var d2 = DateTime.Now;
for(var i=0; i<1000000000;i++)
{
if (s is null or "")
{
Console.WriteLine("Hello Again");
}
}
Console.WriteLine("Method2: " + (DateTime.Now - d2).TotalMilliseconds);
Console.WriteLine("End");
}
}
Result (Duration in miliseconds):
Method1: 2959.476
Method2: 4676.6368
They're effectively the same:
https://learn.microsoft.com/en-us/dotnet/api/system.string.isnullorempty?view=net-5.0#remarks
Remarks
IsNullOrEmpty is a convenience method that enables you to
simultaneously test whether a String is null or its value is
String.Empty. It is equivalent to the following code:
bool TestForNullOrEmpty(string s)
{
bool result;
result = s == null || s == string.Empty;
return result;
}
string s1 = null;
string s2 = "";
Console.WriteLine(TestForNullOrEmpty(s1));
Console.WriteLine(TestForNullOrEmpty(s2));
// The example displays the following output:
// True
// True
I have this code, to get the messages from database:
[HttpGet]
public string RecieveMessagesFromDatabase(int ChatID)
{
// Before - Query formatting and execution
while(reader.Read())
{
for (int i = 0; i < UserList.Count; i++)
{
if (ChatID == 1)
{
TempMessageStorage.Add(
new Messages(reader["Message"].ToString(), Convert.ToInt32(reader["SenderID"]),
reader["Date"].ToString(), ReceiverID, groupid));
} // Public Chat
else if (ChatID == 2)
{
if (i == Convert.ToInt32(reader["SenderID"]) || i == Convert.ToInt32(reader["ReveiverID"]))
{
TempMessageStorage.Add(
new Messages(reader["Message"].ToString(), Convert.ToInt32(reader["SenderID"]),
reader["Date"].ToString(), ReceiverID, groupid));
}
} // Private Chat
else if(ChatID == 3)
{
if (i == Convert.ToInt32(reader["SenderID"]) || i == Convert.ToInt32(reader["ReveiverID"]))
{
TempMessageStorage.Add(
new Messages(reader["Message"].ToString(), Convert.ToInt32(reader["SenderID"]),
reader["Date"].ToString(), ReceiverID, groupid));
}
} // Group Chat
}
}
return JsonSerializer.Serialize(TempMessageStorage);
}
catch(Exception ex)
{
Content(ex.Message);
}
finally
{
reader.Close();
_Connection.Connection.Close();
}
return null;
}
In TempMessageStorage Messages are present, and it is not empty. But JSON returns the empty result. But not really empty. It seems to get the number of records, but they are empty. That's how it looks like - https://prnt.sc/u3d8gc
Messages class contains
I'm certain that in C# ASP.NET APIs you don't need to serializer/deserialize object because they will be returned as a json by default, image
[HttpGet]
public object Get()
{
return new { number = 1, word = "hi" };
}
In the client side they would get a json describing that object, you don't need to serialize. The json would be like this:
{"number":1,"word":"hi"}
I would like to know if there is a quick way (Maybe with TimeSpan) to convert a duration time formatted string like 17.24s or 20.79m or 1.3h to seconds format like 17 for 17.24s, 1260 for 20.79m and 4699 for 1.3h.
Thanks for suggestions.
Let's start from math:
20.79 minutes == 20.79 * 60 seconds == 1247 seconds
1.3 hours == 1.3 * 3600 seconds == 4680 seconds
I can't see 1260 or 4699, that's why I'll stick to simple math, I'll mark with \\TODO: the code which should be modified if you insist on different logic.
For different suffixes, let's extract model:
private static Dictionary<string, Func<double, TimeSpan>> s_Builders =
new Dictionary<string, Func<double, TimeSpan>>(StringComparer.OrdinalIgnoreCase) {
{ "", x => TimeSpan.FromSeconds(x)},
{ "s", x => TimeSpan.FromSeconds(x)},
//TODO: if you insist on 1260, put required logic here
{ "m", x => TimeSpan.FromMinutes(x)},
//TODO: if you insist on 4699, put required logic here
{ "h", x => TimeSpan.FromHours(x)},
{ "d", x => TimeSpan.FromDays(x)},
};
Time to implement TryMyParse method:
public static bool TryMyParse(string value, out TimeSpan result) {
result = default;
if (string.IsNullOrWhiteSpace(value))
return false;
string suffix = s_Builders
.Keys
.OrderByDescending(key => key.Length)
.FirstOrDefault(key => value.EndsWith(key, StringComparison.OrdinalIgnoreCase));
if (null == suffix)
return false;
else if (double.TryParse(value.Substring(0, value.Length - suffix.Length),
out double number)) {
try {
result = s_Builders[suffix](number);
return true;
}
catch (OverflowException) {
return false;
}
catch (ArgumentException) {
return false;
}
}
return false;
}
Finally, MyParse is very simple:
public static TimeSpan MyParse(string value) =>
TryMyParse(value, out var result)
? result
: throw new FormatException($"{value} is not a valid time");
Demo:
string[] tests = new string[] {
"17.24s",
"20.79m",
"1.3h",
};
string demo = string.Join(Environment.NewLine, tests
.Select(test => $"{test,6} :: {Math.Round(MyParse(test).TotalSeconds),4}"));
Console.Write(demo);
Outcome:
17.24s :: 17
20.79m :: 1247
1.3h :: 4680
Timespan does have a Parse method that accepts a string parameter but it uses a different input format than what you want. See more information here: https://learn.microsoft.com/en-us/dotnet/api/system.timespan.parse?view=netcore-3.1
You'll have to make your own parse method to convert a string input to a Timespan and use the TotalSeconds property to get the number of seconds.
If you go this route I would suggest starting by writing a unittest first containing all the inputs considered valid and their expected result. From there you can implement your parse method and verify it.
namespace StackOverflow
{
public class Tests
{
[Fact]
public void TestTimespanStringConversion()
{
// Test cases go here...
Assert.Equal(TimeSpan.FromHours(1.2), "1.20h".AsTimeSpan())
}
}
public static class StringExtensions
{
public static TimeSpan AsTimeSpan(this string input)
{
// Conversion logic goes here...
return new TimeSpan();
}
}
}
Thanks for the suggestions guys! I'm very appricate it. Here is my solution that workes for me:
private int timeParser(string pTime) {
int iResult = 0;
double dTime = 0.0;
NumberStyles style = NumberStyles.Number;
CultureInfo culture = CultureInfo.InvariantCulture;
if(pTime.Contains("ms")) {
if(Double.TryParse(pTime.Trim().Replace("ms", ""), style, culture, out dTime)) {
iResult = (int)Math.Round(TimeSpan.FromMilliseconds(dTime).TotalSeconds);
} else {
throw new FormatException("Unable to convert " + pTime);
}
} else if(pTime.Contains("s")) {
if(Double.TryParse(pTime.Trim().Replace("s", ""), style, culture, out dTime)) {
iResult = (int)Math.Round(TimeSpan.FromSeconds(dTime).TotalSeconds);
} else {
throw new FormatException("Unable to convert " + pTime);
}
} else if(pTime.Contains("m")) {
if(Double.TryParse(pTime.Trim().Replace("m", ""), style, culture, out dTime)) {
iResult = (int)Math.Round(TimeSpan.FromMinutes(dTime).TotalSeconds);
} else {
throw new FormatException("Unable to convert " + pTime);
}
} else if(pTime.Contains("h")) {
if(Double.TryParse(pTime.Trim().Replace("h", ""), style, culture, out dTime)) {
iResult = (int)Math.Round(TimeSpan.FromHours(dTime).TotalSeconds);
} else {
throw new FormatException("Unable to convert " + pTime);
}
} else if(pTime.Contains("d")) {
if(Double.TryParse(pTime.Trim().Replace("d", ""), style, culture, out dTime)) {
iResult = (int)Math.Round(TimeSpan.FromDays(dTime).TotalSeconds);
} else {
throw new FormatException("Unable to convert " + pTime);
}
} else {
throw new FormatException(pTime + " is not a valid timeformat");
}
return iResult;
}
I have a class that I check the index or the length of the string. And I want to write a Nunit Negative Test:
if the length of the string Out of Range the Nunit Test is true. Or the first index is digit "false" the Nunit Test is true.
What i try:
My CheckKeyClass:
public void SetKey(string keyToAnalyse)
{
Line = new string[keyToAnalyse.Length];
int nummeric;
bool num;
if (Line.Length == 0 || Line.Length < 24)
{
throw new Exception("Index Out of Range " + Line.Length);
}
// Ist Product a Character
num = int.TryParse(Line[0], out nummeric);
if (!num)
{
if (Line[0] == "K")
{
Product = 0;
}
}
else
{
throw new Exception("The Productnumber is not right: " + Line[0] ". \nPlease give a Character.");
}
}
My Nunit Test:
[Test]
public void NegativeTests()
{
keymanager.SetKey("KM6163-33583-01125-68785");
// Throws<ArgumentOutOfRangeException>(() => keymanager.Line[24]);
}
// ExpectedException Handling
public static void Throws<T>(Action func) where T : Exception
{
var exceptionThrown = false;
try
{
func.Invoke();
}
catch (T)
{
exceptionThrown = true;
}
if (!exceptionThrown)
{
throw new AssertFailedException(String.Format("An exception of type {0} was expected, but not thrown", typeof(T)));
}
}
So if the Line.length Out of Range the Test must be green also true.
How do I use that the Tests is true?
thx
Use Assert.Throws()
string keyHasLengthOf24 = "KM6163-33583-01125-68785";
var ex = Assert.Throws<Exception>(() => keymanager.SetKey(keyHasLengthOf24));
Assert.That(ex.Message, Is.EqualTo("Index Out of Range "));
See this SO answer for further detail.
i am using command line arguments and if conditions are used to check the input values but it is not looking good can i change it to switch but i have no idea how to change it my code is
if (args.Length > 0 && args.Length == 4)
{
string programName = args[0];
string file1= args[2];
string file2= args[3];
bool flag = false;
int num= 0;
bool isNum = Int32.TryParse(args[1].ToString(), out num);
if (!(programName.Equals("Army")))
{
Console.WriteLine("Error");
}
if (!Int32.TryParse(args[1].ToString(), out isNum ))
{
Console.WriteLine("value should be a number");
}
if (!File.Exists(file1))
{
Console.WriteLine("file 1 does not exist");
}
if (!File.Exists(file2))
{
Console.WriteLine("file 2 does not exist");
}
A switch statement isn't really called for here. That's useful when you have a single value and need to select from a series of possible mutually-exclusive steps based on that value. But that's not what you're doing here. These aren't a chain of if/else if statements keying off a value, these are more like guard clauses. All of them need to run in order to determine all of the output to show to the user.
You can shorten the code by removing the curly braces:
if (!(programName.Equals("Army")))
Console.WriteLine("Error");
if (!Int32.TryParse(args[1].ToString(), out isNum ))
Console.WriteLine("value should be a number");
if (!File.Exists(file1))
Console.WriteLine("file 1 does not exist");
if (!File.Exists(file2))
Console.WriteLine("file 2 does not exist");
You could also extract these lines of code into their own method, which would make the Main method a little cleaner. You could even extract the conditional checks themselves into very small methods to make it more prose-like for readability. But the conditional structure itself doesn't really need to change.
You can create class which will be responsible for retrieving and checking your application arguments. E.g. if your application has name Zorg, you can create following class:
public class ZorgConfiguration
{
private string num;
private string programName;
private string file1;
private string file2;
public static ZorgConfiguration InitializeFrom(string[] args)
{
if (args.Length < 4)
throw new ZorgConfigurationException("At least 4 arguments required");
return new ZorgConfiguration {
ProgramName = args[0],
Num = args[1],
File1 = args[2],
File2 = args[3]
};
}
// to be continued
}
As you can see, it's responsibility is to hold application settings. It has static method for creating instance of configuration from args array. This method checks if arguments count correct and then initializes each property of configuration class with appropriate argument. Checking argument value moved to properties:
public string ProgramName
{
get { return programName; }
private set {
if (value == "Army")
throw new ZorgConfigurationException("Error");
programName = value;
}
}
public string Num
{
get { return num; }
private set {
int i;
if (!Int32.TryParse(value, out i))
throw new ZorgConfigurationException("value should be a number");
num = value;
}
}
public string File1
{
get { return file1; }
private set {
if (!File.Exists(value))
throw new ZorgConfigurationException("file 1 does not exist");
file1 = value;
}
}
Each property is responsible for verifying corresponding argument value. If value is incorrect, then custom ZorgConfigurationException (that is simply class inherited from Exception) is thrown.
Now main application code looks very clean:
try
{
var config = ZorgConfiguration.InitializeFrom(args);
// you can use config.File1 etc
}
catch (ZorgConfigurationException e)
{
Console.WriteLine(e.Message);
// exit application
}
I use this class to parse command line arguments, I've found it somewhere, but I can't remember where:
public class Arguments
{
// Variables
private StringDictionary Parameters;
// Constructor
public Arguments(string[] Args)
{
Parameters = new StringDictionary();
Regex Spliter = new Regex(#"^-{1,2}|^/|=|:",
RegexOptions.IgnoreCase | RegexOptions.Compiled);
Regex Remover = new Regex(#"^['""]?(.*?)['""]?$",
RegexOptions.IgnoreCase | RegexOptions.Compiled);
string Parameter = null;
string[] Parts;
// Valid parameters forms:
// {-,/,--}param{ ,=,:}((",')value(",'))
// Examples:
// -param1 value1 --param2 /param3:"Test-:-work"
// /param4=happy -param5 '--=nice=--'
foreach (string Txt in Args)
{
// Look for new parameters (-,/ or --) and a
// possible enclosed value (=,:)
Parts = Spliter.Split(Txt, 3);
switch (Parts.Length)
{
// Found a value (for the last parameter
// found (space separator))
case 1:
if (Parameter != null)
{
if (!Parameters.ContainsKey(Parameter))
{
Parts[0] =
Remover.Replace(Parts[0], "$1");
Parameters.Add(Parameter, Parts[0]);
}
Parameter = null;
}
// else Error: no parameter waiting for a value (skipped)
break;
// Found just a parameter
case 2:
// The last parameter is still waiting.
// With no value, set it to true.
if (Parameter != null)
{
if (!Parameters.ContainsKey(Parameter))
Parameters.Add(Parameter, "true");
}
Parameter = Parts[1];
break;
// Parameter with enclosed value
case 3:
// The last parameter is still waiting.
// With no value, set it to true.
if (Parameter != null)
{
if (!Parameters.ContainsKey(Parameter))
Parameters.Add(Parameter, "true");
}
Parameter = Parts[1];
// Remove possible enclosing characters (",')
if (!Parameters.ContainsKey(Parameter))
{
Parts[2] = Remover.Replace(Parts[2], "$1");
Parameters.Add(Parameter, Parts[2]);
}
Parameter = null;
break;
}
}
// In case a parameter is still waiting
if (Parameter != null)
{
if (!Parameters.ContainsKey(Parameter))
Parameters.Add(Parameter, "true");
}
}
// Retrieve a parameter value if it exists
// (overriding C# indexer property)
public string this[string Param]
{
get
{
return (Parameters[Param]);
}
}
}
I use it this way:
var cmdParams = new Arguments(args);
if (cmdParams["File"] != null && parametros["cmdParams"] == "Filename.txt) { }
Hope it helps!
Command line arguments can get complicated if there are different functions and arguments..
Best way is to tokenize your arguments, function switch examples are /p /a, or -h, -g etc...Your cmd arg parser looks for these tokens (pattern) - once found you know which cmd it is.. Have switch - case or any other mechanism for this. Also tokenise the other data arguments. Hence you have two sets of arguments - easy to manage.