How to take a Use Case to Unit Test - c#

Here's my Use Case
To start writing unit tests in TDD, I need to come up with classes and methods to test, e.g. ClassUnderTest.MethodUnderTest()
The nouns are: Candidate, Admin, User, Account, Credentials, Password, ResumeWidget (the system), and last but not least, SomeOtherAbstractionIDidNotThinkOf (e.g. SecurityService).
The verbs are: Login(), Logout(), Register(), CreateAccount(), RecoverPassword(), Unlock(), ResetPassword(), Lockout(), and last but not least, SomeOtherActionIDidNotThinkOf().
To make this question most simple, let's see if we can stick with Login(). Let me see if I can start a Unit Test for that method.
Would you have a Login method somewhere?
If so, what Class would you put it in? Why?
If not, what Class and Method would you use? And Why?

I give you a small hint about how to start TDD. First, think about how to design your software based on your use case.(Ex: Account class can contain login, logout and etc., methods)
[TestFixture]
public class AccountTest
{
public Account underTest;
[SetUp]
public void setUp()
{
underTest = new Account();
}
[Test]
public void TestLoginWithValidCredentials()
{
bool isValid = underTest.Login('userName', 'password');
Assert.True(isValid );
}
[Test]
public void TestLoginWithInValidCredentials()
{
bool isValid = underTest.Login('', '');
Assert.False(isValid );
}
[Test]
//Assert Expected Lockout exception here
public void TestLockoutByPassingInValidCredentialsMoreThan5Times()
{
for (int i =0; i< 5; i++)
{
bool isValid = underTest.Login('', '');
Assert.False(isValid );
}
// the system should throw an exception about lockout
underTest.Login('', '');
}
[Test]
public void TestCreateAccount()
{
//Register event can directly call this method
bool isCreated = underTest.Create(/*User Object*/);
Assert.True(isCreated );
}
[Test]
public void TestLogout()
{
bool success = underTest.Logout('userName');
Assert.True(success);
}
[Test]
public void TestReset()
{
// both Unlock and RecoverPassword event can share this method
bool success = underTest.Reset('userName');
// mock the password reset system and return the expected value like 'BSy6485TY'
Assert.AreEqual('BSy6485TY', password);
}
}
Updated: Added more test cases to help you to design your system.

Related

How to run Multiple [TestMethod] in order?

i am asking how to run multiple test method in order that they are in same file.
For example i have this Unit Test File name
public class UniTest1
{
[TestMethod]
public void Login()
[TestMethod]
public void Logout()
[TestMethod]
public void SignIn()
[TestMethod]
public void ForgetPassword()
}
I want them in this order:
Login()
Logout()
ForgetPassword()
SignIn()
Just to clarify i want this order to check if this email already exist or not
If you structure your test cases to contain the code for the setup, action and assertions for that particular case, you do not need to run them in any particular order. A good advice would be to aim to not have any dependencies between the test cases, for instance, you should need to depend upon a "Login" test to have run prior to "LogOut". Instead the setup of the test code in the "LogOut" case would initiate the logged in session and set the stage for the "LogOut" action to happen.
If you find that multiple test cases share common setup code and teardown code, you could use the TestInitialize and TestCleanup properties on some methods, as such:
namespace UserInteractionTests
{
[TestClass]
public class UserAuthenticationTestt
{
[TestInitialize]
public void TestSetup()
{
/* Put your common initialization code here */
}
[TestMethod]
public void AnAuthorizedUserCanLogin()
{
/* put your setup, action and assertion here
from your system under test
*/
}
[TestMethod]
public void ALoggedInUserCanLogOut()
{
/* put your setup, action and assertion here
from your system under test
*/
}
[TestCleanup]
public void TestCleanup()
{
/* Put your common teardown code here.. */
}
}
}
You're setting up one big Test with multiple steps but not four dedicated tests.
Here an example:
public class UniTest1
{
[TestMethod]
public void LoginSuccess()
{
// Try to Log in
o.Login("user", "pw");
Assert.AreEqual(true, o.ImLoggedIn);
}
[TestMethod]
public void LoginWrongPw()
{
// Try to Log in
o.Login("user", "wrongpw");
Assert.AreEqual(false, o.ImLoggedIn);
}
[TestMethod]
public void LogOutSuccess()
{
// Login
o.Login("user", "pw");
// Check if steup is completed
Assert.AreEqual(true, o.ImLoggedIn);
bool ok = o.LogOut();
Assert.AreEqual(true, ok);
}
[TestMethod, ExpectedException(NotLoggedInException)]
public void LogOutNoLogout()
{
// Try to Log in
Assert.AreEqual(false, o.ImLoggedIn);
bool ok = o.LogOut();
}
}
As you can see every test is independend from the others.
If you need a logout-test you have to setup the environment for it and not "hope" that other tests to so.

AutMocker with Setup not working properly

I am trying to use Moq.Automock in one of my projects, which I have not used before. Please see the code below:
[TestFixture]
public class BusinessLayerTests
{
List<Denomination> expectedDenominations;
AutoMocker mocker = new AutoMocker();
UKCurrency Currency;
IDenominationFactory DenominationFactory;
[OneTimeSetUp]
public void Initialize()
{
Currency = mocker.CreateInstance<UKCurrency>();
DenominationFactory = mocker.CreateInstance<DenominationFactory>();
mocker.Setup<UKCurrency>(x => x.CurrencyDenominations()).Returns(CurrencyDenominations());
}
public System.Collections.Generic.IEnumerable<decimal> CurrencyDenominations()
{
yield return 50M;
}
}
I believe the code above shows that I have created a mock object called: Currency. I believe the line starting: mocker.Setup should ensure that the local method called: CurrencyDenominations is called. However, this does not happen. The method called: CurrencyDenominations in UKCurrency is called.
What am I doing wrong?
You need to get the underlying mock and apply the setup on that.
[OneTimeSetUp]
public void Initialize() {
Currency = mocker.CreateInstance<UKCurrency>();
DenominationFactory = mocker.CreateInstance<DenominationFactory>();
var currencyMock = mocker.GetMock<UKCurrency>();
currencyMock.Setup(_ => _.CurrencyDenominations()).Returns(CurrencyDenominations());
}
provided UKCurrency.CurrencyDenominations is virtual and able to be overridden.

Selenium Webdriver - Test fails assert if not running in Debug Mode C# visual studio

I have been teaching myself Selenium over the past few weeks and have started writing my own tests, I can get all my happy flow tests to work fine but my first attempt at writing a test to check an error message is not working.
As an overview the test is really simple:
Enter an invalid postcode into a search box
click search
Assert the screen shows an error message below the search box.
I know the logic of my code works as when I run the positive flow (enter postcode, click search, new page opens) the automated test is working fine. Also when I run the test in debug mode and step through the failed Assert the test passes with the error message picked up.
My Test code
[TestClass]
public class invalidSearch
{
[TestInitialize]
public void Init()
{
driver.Initialize();
}
[TestMethod]
public void Invalid_Location_Returns_Error()
{
Homepage.GoTO_HomePage();
SearchPage.enterSearch("CFYUGHGYHYTDFD").Search();
Assert.IsTrue(SearchErrorMessage.IsInValidLocation("Please enter a valid location or postcode", "Validation Fails"));
}
[TestCleanup]
public void Cleanup()
{
driver.Close();
}
My assert class
public class SearchErrorMessage
{
public static bool IsInValidLocation(string InvalidLocation)
{
var ErrorMessage = driver.Instance.FindElement(By.XPath("/html/body/header/div/div[4]/div/div/div[2]/div[1]/form/div[2]/span[2]"));
bool result = ErrorMessage.Text.Contains(InvalidLocation);
return result;
}
My driver Class
public class driver
{
public static IWebDriver Instance { get; set; }
public static void Initialize()
{
Instance = new ChromeDriver(#"C:\Users\xxxxxx.xxxxxx\Documents\Visual Studio 2015\Drivers\Chrome");
Instance.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(10));
}
public static void Close()
{
Instance.Close();
}
You probably just need an explicit wait, try this:
public static bool IsInValidLocation(string invalidLocation)
{
By selector = By.XPath("/html/body/header/div/div[4]/div/div/div[2]/div[1]/form/div[2]/span[2]");
// You might want to research how to construct stable xpaths/selctors
new WebDriverWait(driver.Instance, TimeSpan.FromSeconds(5)).Until(ExpectedConditions.ElementIsVisible(selector));
var ErrorMessage = driver.Instance.FindElement(selector);
bool result = ErrorMessage.Text.Contains(invalidLocation);
return result;
}
The above code will give that message up to 5 seconds to appear, and will throw a timeout exception if it doesn't appear within 5 seconds. You can adjust it to wait longer if needed.

C# - MS Test - Create a test that runs another test first

In our application, I have created a login test for our website. If this test is successful then login is successful. Now to create tests for other parts of the website, I need to perform login first.
Is there a way so that all the other tests that I will create will run the login test first? For example: is it possible to create a custom login test attribute that I can put on all other test methods, so that they will run login first? But then I also need the return value from that login test !
If not, then I will have to just write a plain C# function that performs login operation and I will need to put that function call, as the first line of every test.
When you're writing unit tests, you are testing each method in isolation. Meaning, the method that you're testing must not, and cannot depend on anything else in order to run.
The reason why you have a problem now, probably is because you broke at least the single responsability principle (the one that states that your class should only have one single reason to be changed). I can assume this because you are stating that your OTHER methods in a class depend on login being successful. Here's how to solve it:
Make an interface for your login method, something like:
public interface ILoginManager{
void Authenticate(string username, string password);
void IsAuthenticated{ get;}
}
Next, using the Dependency Inversion Principle, add this interface to your class with methods in it:
public class MyWorkerClass
{
private readonly ILoginManager _loginManager;
public MyWorkerClass(ILoginManager loginManager){
_loginManager = loginManager;
}
public bool LogOnUser(string userName, string password){
_loginManager.Authenticate(userName, password);
return _loginManager.IsAuthenticated;
}
}
Now, in all your tests, you can mock out the LoginManager, and set your expectations there, i.e.
[TestMethod]
public void SomeMethod_UserIsAuthenticated_InvokesSomeOtherMethod()
{
// Arrange
GetMockFor<ILoginManager>().SetupGet(lm => lm.Authenticated).Returns(true);
// Act
var result = Instance.SomeMethod();
// Assert
GetMockFor<ISomeOtherInterface>()
.Verify(o => o.SomeOtherMethod(), Times.AtLeastOnce() );
}
What about a base class?
[TestClass]
public class AuthenticatedTest
{
[TestInitialize]
public void TestInitialize()
{
// login
}
}
[TestClass]
public class MyTests : AuthenticatedTest
{
[TestMethod]
public void Whatever()
{
// already logged in.
}
}
You should not write tests which rely on other tests. If you need to log in before, you have to log n before, not "run the login test". It is probably not much difference of the code, but of the concept.

Unit Testing With Computer Owned States

I am writing a unit test for when my computer receives/makes a phone call.
The methods being tested are the events that handle the incoming/outgoing call. If the caller is not an approved caller then the call is rejected.
The code works fine, but I can't really find anything to test against for my unit test. The problem is that the actual state of "if my computer is in a call or not" is not controlled my by class. Only the computer knows if a call is currently connected or not.
I am hoping that there are some Unit Test Guru's out there than can tell me what to do to test this scenario. I do not want to create a dummy var that has no relation to my code just to make my unit test pass.
To make this a bit more concrete here is my unit test:
private DeviceMediator deviceMediator;
private IDeviceControlForm deviceControlForm;
private IDataAccess data;
private ICallMonitor callMonitor;
// Use TestInitialize to run code before running each test
[TestInitialize()]
public void MyTestInitialize()
{
deviceControlForm = MockRepository.GenerateStub<IDeviceControlForm>();
data = MockRepository.GenerateStub<IDataAccess>();
callMonitor = MockRepository.GenerateStub<ICallMonitor>();
deviceMediator = new DeviceMediator(deviceControlForm, data)
{CallMonitor = callMonitor};
}
[TestMethod]
public void TestHandleIncomingCall()
{
//Arrange
//Act
deviceMediator.OnIncomingCall(null, new CallState(),
new CallInfoState());
//Assert
// I could not find anything to feasably test on this.
Assert.IsTrue(true);
}
and here is the method it is calling:
public void OnIncomingCall(Call call, CallState callState,
CallInfoState callInfoState)
{
// See if this call is on our list of approved callers
bool callApproved = false;
foreach (PhoneContact phoneContact in Whitelist)
{
if (phoneContact.PhoneNumber == call.CallerID)
callApproved = true;
}
// If this is not an approved call then
if (!callApproved)
CallMonitor.Hangup();
}
Turns out I just did not know enough about Rhino Mocks. The answer to this issue can be found here.
This is my code with that answer incorporated.
Unit Test:
[TestMethod]
public void TestHandleIncomingCall()
{
//Arrange
callMonitor.InCall = true;
// This is the magic. When Hangup is called I am able to set
// the stub's InCall value to false.
callMonitor.Expect(x => x.Hangup()).Callback(() => WhenCalled(invocation =>
{
callMonitor.InCall = false;
});
List<PhoneContact> whiteList = FillTestObjects.GetSingleEntryWhiteList();
data.Expect(x => x.GetWhiteListData()).Return(whiteList);
const string invalidPhoneNumber = "123";
//Act
deviceMediator.HandleIncomingCall(invalidPhoneNumber);
//Assert
Assert.IsFalse(callMonitor.InCall);
}
I had to change my code to this because Call has an internal constructor:
public void OnIncomingCall(Call call, CallState callState,
CallInfoState callInfoState)
{
// See if this call is on our list of approved callers
HandleIncomingCall(call.CallerID);
}
public void HandleIncomingCall(string callNumber)
{
bool callApproved = false;
foreach (PhoneContact phoneContact in Whitelist)
{
if (phoneContact.PhoneNumber == callNumber)
callApproved = true;
}
// If this is not an approved call then
if (!callApproved)
CallMonitor.Hangup();
}
It's called dependancy injection. You make your code act on an interface that mimics the real Phone api, and supply your own controllable implementation for the tests. There are systems out there like Spring.Net that make this easier to do.
Here's a couple things you could do:
You could create a mock WhiteList collection that will contain a certain set of the PhoneContacts, and then call OnIncomingCall with PhoneContacts that are or are not in the WhiteList and then check the CallMonitor (or the Call object itself, I suppose) to see if the call is in the correct state. So Assert.IsTrue(call.IsConnected) or Assert.IsFalse(call.IsConnected) depending on the scenario you're testing.
You could also see if the method handles Call objects that are null or that are not in the correct state at the point where this method is being called.

Categories