I'm doing unit testing with a class library and I'm stuck on how to test the method that need to test scenarios like check if a password with less than 8 characters cannot be accepted, check if a password with 8 or more characters can be accepted and check if a password with space in the front cannot be accepted.
The code below is from the class library.
public class PasswordChecker
{
public bool CheckPassword(string pwd)
{
if (pwd.Length >= 8 && !pwd.StartsWith(""))
{
return true;
}
else
{
return false;
}
}
}
The code below is from the testing project.
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using 12kiajunPA03;
namespace PasswordCheckerTest
{
[TestClass]
public class PasswordCheckerTest
{
[TestMethod]
public void Checkpassword()
{
string pwd = "1234qa1";
Checkpassword password = new Checkpassword("John", pwd);
try
{
}
catch
{
}
}
}
}
I imagine it would look something like this:
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using 12kiajunPA03;
namespace PasswordCheckerTest
{
[TestClass]
public class PasswordCheckerTest
{
[TestMethod]
public void Checkpassword8CharsLong()
{
string validPassword = "12345678";
string invalidPassword = "abc";
PasswordChecker checker = new PasswordChecker();
Assert.IsTrue(checker.CheckPassword(validPassword));
Assert.IsFalse(checker.CheckPassword(invalidPassword));
}
}
}
Using the same idea, you could write additional tests that check for other criteria that the passwords must meet.
Related
I have a simple function that takes Client and Supplier data and then calculates tax based on where they live and other information:
static int CountTax(Supplier tiek, Client kl, bool same_country)
{
if ( !tiek.is_PVM_payer)
return 0;
else
{
if (!kl.EU)
return 0;
else
{
if (same_country)
return kl.x;
else
{
if (kl.is_PVM_payer)
return 0;
else
return kl.x;
}
}
}
}
Now I am required to write tests for this function. It is the first time I am encountering tests. I am using XUnit testing. And my test class looks like this:
using System;
using Xunit;
namespace CountTax_tests
{
public class UnitTest1
{
[Theory]
[InlineData(typeof(Client))]
public void Tax_is_0()
{
// arrange
int expectedVal = 0;
int actualVal;
/// act
actualVal = MyProgram.MyprogramCode.CountTax(supplier, client, same_country);
// assert
Assert.Equal(expectedVal, actualVal);
}
[Fact]
public void PVM_is_x()
{
int expectedVal = x;
int actualVal;
actualVal = MyProgram.MyprogramCode.CountTax(supplier, client, same_country);
Assert.Equal(expectedVal, actualVal);
}
}
}
But how do I pass my Client and Supplier parameters to that test? Please help me and lead on a path because I am completely new and nothing is clear to me even after many tutorials...
Maybe I have to use [Theory]? Or maybe [Fact]? Or maybe it is impossible to pass classes as parameters?
Also, [InlineData(typeof(Client))] is being underlined in red and is not working.
I am building a simple Airport program where planes can only take off / land if the weather is sunny and not stormy. This depends on the Weather class (which randomises the weather between sunny and stormy). However, for my tests, I want to mock the weather so I can test for all cases.
Here is my Weather.cs:
using System;
namespace ClassNameWeather
{
public class Weather
{
public Weather()
{
}
public string Forecast()
{
Random random = new Random();
var weather = random.Next(1, 11);
if (weather == 1 || weather == 2)
{
return "stormy";
}
else
{
return "sunny";
}
}
}
}
Here is my Airport.cs:
using System;
using System.Collections.Generic;
using ClassNamePlane;
using ClassNameWeather;
namespace ClassNameAirport
{
public class Airport
{
private string _AirportName { get; set; }
public List<Plane> planes;
private Weather _weather = new Weather();
public Airport(string _airportName, Weather weather)
{
planes = new List<Plane>();
_AirportName = _airportName;
}
public void Land(Plane plane)
{
if (_weather.Forecast() != "stormy")
{
planes.Add(plane);
Console.WriteLine($"{ plane.Name } has landed at {_AirportName}");
}
else
{
throw new Exception("It's too stormy to land");
}
}
public void TakeOff(Plane plane)
{
if (_weather.Forecast() != "stormy")
{
planes.Remove(plane);
Console.WriteLine($"{ plane.Name } has departed from {_AirportName}");
}
else
{
throw new Exception("It's too stormy to take off");
}
}
public int GetPlaneCount()
{
Console.WriteLine($"Number of planes at {_AirportName}: {planes.Count}");
return planes.Count;
}
public void GetPlaneNames()
{
planes.ForEach(plane => Console.WriteLine((plane as Plane).Name));
}
public List<Plane> GetPlaneList()
{
return planes;
}
}
}
And here is the test that I'm trying to use the mock in:
using NUnit.Framework;
using ClassNameAirport;
using ClassNamePlane;
using ClassNameWeather;
using Moq;
namespace AirportTest
{
public class AirportTest
{
Airport airport = new Airport("TestAirport", weather);
Plane plane = new Plane("TestPlane");
[Test]
public void PlaneCanLand()
{
var weather = new Mock<Weather>();
weather.Setup(x => x.Forecast()).Returns("sunny");
airport.Land(plane);
Assert.IsTrue(airport.planes.Contains(plane));
}
public void PlaneCanTakeOff()
{
airport.Land(plane);
airport.TakeOff(plane);
Assert.IsFalse(airport.planes.Contains(plane));
}
}
}
This line: Airport airport = new Airport("TestAirport", weather); is not working, saying the name weather does not exist.
Can anyone help me to make sure I am using Moq correctly? I'm new to C# and any advice is much appreciated.
Thank you!
UPDATE
I have fixed this, but now receive the following error:
System.NotSupportedException : Unsupported expression: x => x.Forecast()
Non-overridable members (here: Weather.Forecast) may not be used in setup / verification expressions.
Does anyone know how to fix this please?
You can introduce interface IWeather like
public interface IWeather
{
string Forecast();
}
Than implement it in Weather class. Pass IWeather reference to AirPort class and setup a mock for that.
var weather = new Mock<IWeather>();
weather.Setup(x => x.Forecast()).Returns("sunny");
...
var airport = new Airport("TestAirport", weather.Object)
And do not initialize it in Airport class directly private Weather _weather = new Weather(); (your constructor argument is not used), do like this
public class Airport
{
private string _AirportName { get; set; }
public List<Plane> planes;
private readonly IWeather _weather;
public Airport(string _airportName, IWeather weather)
{
planes = new List<Plane>();
_weather = weather;
}
...
}
You have not declared the variable weather. I suggest that you create an Initialize method and attribute it with TestInitialze
[TestInitialize]
public void TestInitialize()
{
var weather = new Mock<Weather>();
var airport = new Airport("TestAirport", weather)
}
I have like below.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
namespace Syncfusion.Gitlab
{
public class Branches
{
public void CreateBranch(List<string> projectName, string sourceBranch, string destinationBranch)
{
}
public void CreateTag(List<string> projectName, string sourceBranch,string tagname)
{
}
public static List<string> GetBranchList(string projectId)
{
}
public static List<ProjectData> GetProjectList()
{
}
}
public class ExcelOperation
{
public void GenerateExcel(List<ProjectDetails> finalExcelData, List<string>projectUrl,List<string>tagsorBranchUrl)
{
}
}
}
I can able to test the method and got the positive output. But I do not know how to test these two method public static List<string> GetBranchList(string projectId), public static List<ProjectData> GetProjectList()
My sample test code is below. Below method is successfully passed in NUnit test.
[TestMethod]
public void CreateTags()
{
List<string> project = new List<string>();
project.Add("test1");
string sourceBranch = "master";
string tagsName = "v1.0.0";
branch.CreateTag(project, sourceBranch, tagsName);
}
How can I test the that two methods?
Update:
I can get the answer with the help of first answer. But Now I have anouther doubt.
How could I test for wrong input? I mean I know that the input I was given Is wrong but I need the green tick mark for that testing. That means the input given is wrong so the output also wrong therfore the testing is right.
In my below image. I need public void GetBranchListforWrongInput() also green tick mark.
How could I do it?
Unit testing static method is pretty much as same as testing non-static methods. It might get complex based on what logic you have in the static method.
But simplest way for your case would be as following.
[TestMethod]
public void TestGetBranchList()
{
string projectId = "someProjectId";
var result = Branches.GetBranchList(projectId);
//Assert if result has expected result.
}
[TestMethod]
public void TestGetProjectList()
{
var result = Branches.GetProjectList();
//Assert if result has expected result.
}
[TestMethod]
public void TestCreateBranch()
{
//Prepare TestData
List<string> projectName = new List<string> {"someProject"};
string sourceBranch = "sourceBranch"
string destinationBranch = "destBranch";
Branches branchesObj = new Branches();
// Call method by passing the test data.
branchesObj.CreateBranch(projectName, sourceBranch, destinationBranch);
}
This should help you resolve your issue.
I need to write a unit test to test if the input is a valid currency value. I have tried several ways, but i don't think it's the correct way to test for currency value.
TEST CASE:
namespace validationUnitTest
{
// Validation rule for checking if the input is a valid currency value
public class CurrencyValidationRule: ValidationRule;
{
private static ValidationRule validationRule;
/// Singleton instance of this <see cref="ValidationRule"/>
public static ValidationRule Instance { get { return validationRule ?? (validationRule = new CurrencyValidationRule()); } }
// performs validation checks on a value
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
if (value is double) return ValidationResult.ValidResult;
string stringValue = value as string;
double result;
return string.IsNullOrEmpty(stringValue) || double.TryParse(stringValue, NumberStyles.Currency, cultureInfo, out result) ? ValidationResult.ValidResult : new ValidationResult(false, "Value must be an number");
}
}
}
UNIT TEST:
namespace validationUnitTest.Tests
{
[TestClass()]
public class CurrencyValidationRuleTests
{
[TestMethod()]
public void ValidateTest()
{
var test = new CurrencyValidationRule();
var expected = new ValidationResult(true, true);
var actual = test.Validate("0", null);
Assert.AreEqual(expected.ErrorContent, actual.ErrorContent);
Assert.AreEqual(expected.IsValid, actual.Isvalid);
Assert.AreEqual(expected.GetHashCode(), actual.GetHashCode());
}
}
}
ANY idea on how I should start my unit test, or what I should be search for? I need some starting points. Any thing is greatly appreciate.
using System;
using System.Linq;
using Xunit;
using MonthlyStatements.Controllers;
using MonthlyStatements.Models;
using System.IO;
using System.Web.Mvc;
namespace UnitTestProject1
{
public class UnitTest1
{
[Theory]
[InlineData(10.20, "System.Double")]
[InlineData(0, "System.Double")]
public void checkValidation(double amt, string ExpectedResult)
{
//Arrange
string actualResult = "";
//Act
//double doubleAmt = double.Parse(amt.ToString());
actualResult = amt.GetType().ToString();
//Assert
Assert.Equal(ExpectedResult, actualResult);
}
}
}
use Xunit instead of nUnit , before start developing we have to conside following
Rules : 1) we test only public methods 2) we have to know input
parameter and out Put parameter like expected Result and Actual result
in above code you used 3 assert it is not correct way,
here you can check data Type of actual result, use xunit [InlineData()] so dont need to repeat code .
I want to create global cs file for all my test projects to keep all my constants and functions.
For example this file for different tests global.cs:
namespace SeleniumTests
{
Public class forAllTests
{
//....
public void Login()
{
wait.Until<IWebElement>((d) => { return d.FindElement(By.Id("login")); });
driver.FindElement(By.Id("login")).SendKeys("login");
wait.Until<IWebElement>((d) => { return d.FindElement(By.Id("password")); });
driver.FindElement(By.Id("password")).SendKeys("password");
}
}
}
And for example another file Program.cs
namespace SeleniumTests
{
Public class Test
{
forAllTests.Login();
//.....
}
}
Its possible or not?
UPD.
Thanks for answers. Yes, I want more specific advice. I am making tests for Firefox, Chrome and Safari. I know about page objects pattern and i am using it. For example some code from me.
Soo some code here(parts 3* 4* - does not works and want to make them correct, please help me). How its works now:
1* Program.cs --
using System;
using System.Web;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using NUnit.Framework;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Safari;
using OpenQA.Selenium.Firefox;
using OpenQA.Selenium.Support.UI;
using OpenQA.Selenium.Support.PageObjects;
using System.Diagnostics;
using System.Threading;
using Microsoft.Office.Interop.Excel;
using Excel = Microsoft.Office.Interop.Excel;
using System.Web;
using System.Linq;
using System.Windows.Forms;
using System.IO;
using System.Windows.Controls;
namespace SeleniumTests
{
[TestFixture]
public class Auth01
{
private bool acceptNextAlert = true;
private LoginPage loginPage;
private PatientsPage patientsPage;
private MainViewPage mainViewPage;
private EmkPage emkPage;
private IWebDriver driver;
private StringBuilder verificationErrors;
private string baseURL;
string drop_down_id;
string drop_down_text;
string url1;
string url2;
string now1;
[SetUp]
public void SetupTest()
{
driver = new FirefoxDriver();
driver.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(10));
baseURL = "http://....";
driver.Navigate().GoToUrl(baseURL + Constants.startUrl);
// driver.Manage().Window.Maximize();
loginPage = new LoginPage();
PageFactory.InitElements(driver, loginPage);
verificationErrors = new StringBuilder();
}
public void login()
{
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
loginPage.Login.Clear();
loginPage.Login.SendKeys("login");
loginPage.Password.Clear();
loginPage.Password.SendKeys("password");
IWebElement myDynamicElement = wait.Until<IWebElement>((d) => { return d.FindElement(By.CssSelector(loginPage.enterbuttonPublic)); });
loginPage.EnterButton.Click();
}
public void drop_down()
{
IWebElement elem = driver.FindElement(By.Id(drop_down_id));
var options = elem.FindElements(By.TagName("option"));
string opt;
string value;
string x;
foreach (IWebElement option in options)
{
opt = option.Text;
value = option.GetAttribute("value");
if (drop_down_text.Equals(opt))
{
x = "//select[#id='" + drop_down_id + "']/option[#value='" + value + "']";
}
}
}
[TearDown]
public void TeardownTest()
{
try
{
driver.Quit();
}
catch (Exception)
{
} Assert.AreEqual("", verificationErrors.ToString());
}
[Test]
public void The0Auth01Test()
{
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
login();
//.....
drop_down_id="id";
drop_down_text = "text";
drop_down();
//...
stopWatch.Stop();
}
static void Main()
{
Auth01 Auth01_1 = new Auth01();
Auth01_1.SetupTest();
Auth01_1.The0Auth01Test();
}
2* AllAuth.cs --- // for all tests
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OpenQA.Selenium;
using OpenQA.Selenium.Firefox;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.IE;
using OpenQA.Selenium.Support.UI;
using OpenQA.Selenium.Support.PageObjects;
using System.IO
;
namespace SeleniumTests
{
public class LoginPage
{
private IWebDriver driver;
const string login = "USERNAME";
public string loginPublic = login;
[FindsBy(How = How.Id, Using = login)]
public IWebElement Login { get; set; }
const string password = "PASSWORD";
public string passwordPublic = password;
[FindsBy(How = How.Id, Using = password)]
public IWebElement Password { get; set; }
const string enterbutton = "button.button-gray";
public string enterbuttonPublic = enterbutton;
[FindsBy(How = How.CssSelector, Using = enterbutton)]
public IWebElement EnterButton { get; set; }
const string notification = "#notification-message";
public string notificationPublic = notification;
[FindsBy(How = How.CssSelector, Using = notification)]
public IWebElement Notification { get; set; }
const string body = "BODY";
public string bodyPublic = body;
[FindsBy(How = How.CssSelector, Using = body)]
public IWebElement Body { get; set; }
public LoginPage() { }
public LoginPage(IWebDriver driver)
{
this.driver = driver;
if (!driver.Url.Contains("http:..."))
{
throw new StaleElementReferenceException("This is not the login page");
}
PageFactory.InitElements(driver, this);
}
}
3* And I dream about:
AllAuth.cs ---
///...
namescpace SeleniumTests
{
/////.....
public class Fantasy
{
private IWebDriver driver;
login()
{
//....
}
drop_down()
{
//...
}
}
}
4* Program.cs ---
///...
namescpace SeleniumTests
{
/////.....
[Test]
public void The0Auth01Test()
{
fantasy.login();
fantasy.drop_down();
}
///...
}
Sure it's possible. Selenium is merely and API accessed through the WebDriver.dll to drive a browser. Any coding structure you want to use can easily be used for this. I have done a 7 layer version for a company and have seen many just write it all in 1, 2, or 3 layers.
The question is what is best for your organization. For example...if you utilize a particular UnitTest Framework then your "tests" will all exist in a unit test project and reference your core functions similar to an API layer. I would recommend at the very least to incorporate this, as repeating code for common controls in your application is really poor for maintainability and best practices.
The above is in layers and not files. Unless you only have like 5 total tests it is really impractical and difficult to maintain trying to put everything into one or two files. I would really recommend using common coding standards and practices to go with Selenium tests, just like regular c# code. The below links are for c# since this is tagged as c#.
Naming conventions: http://msdn.microsoft.com/en-us/library/ff926074.aspx
Framework Guidelines: http://msdn.microsoft.com/en-us/library/ms229042.aspx
Standards Guidlelines: http://blogs.msdn.com/b/brada/archive/2005/01/26/361363.aspx
Many more if you google it...If you would like more specific advice please add more details to your question, that indicate what your project is, how many tests, specifics of the type of web application and how many different browser types are supported, does it support mobile, database usage, team size, etc...All factor into a good design
UPDATE:
It looks like you are on the right path, but you will need to setup your driver and pass it to the functions...or use a public/protected variable that is the same for all. The way you have it now it looks like it is starting a new driver every time you call a separate function/method which of course won't work.
So put your setup at the top of your test file (#3) with a single test method in (#4) to "setup". When (#4) first test is called the setup will instantiate your driver and save it in (#3). Then pass that driver variable into all your functions on (#3->#2) so that they execute on the same driver instance. The actual setup call should be in (#3) but called similar with the fantasy.setup(); from (#4). Similarly when you update your page object you pass the existing driver into it and overwrite the existing page object with the new page object...unless you want to keep a bunch of different pages...watch memory usage. This will allow your methods to not have to worry about the driver handling at all. This will also allow you to kick off multiple test threads and each will maintain their own drivers. Then when you call the fantasy.login(); it will go to that method in (#3) and call the (#2) method and pass the private driver from memory in (#3) to (#2) method for execution purposes.
Please let me know if that isn't clear...