hoakey
hoakey

Reputation: 998

MS Unit testing example

I'm struggling to get my head around unit testing. I've been following examples from both Nerd dinner and pro asp.net MVC framework, but as soon as I attempt my own quickly become stuck. As a test I have tried to build a validation class that simply using login information - usename and password to return a user from a repository. I've used this example as it's pretty simple to imagine what tests one might perform: Is_Password_Valid, Is_Username_Valid etc.

I've spent far too long trying to get my noggin around this. Could any one provide an example of how they might approach this as a unit test? I think once I've cracked this I'll be away.

//Arrange
string email = "[email protected]";
string password = "test";

//Arrange
List<Customer> customer = new List<Customer>();

customer.Add(new Customer { CustomerId = 1, Email = email, Password = "best", FirstName = "test", LastName = "wods", Sex = true });
mockRepos = new Moq.Mock<ICustomerRepository>();
mockRepos.Setup(x => x.GetCustomerByPasswordUsername(email, password)).Returns(customer.First());
Authenticate auth = new Authenticate(mockRepos.Object);

//Act
var result = auth.Login(email, password);

//Assert
//this is where I start to become unstuck??????

Upvotes: 4

Views: 6941

Answers (2)

Dean Hiller
Dean Hiller

Reputation: 20210

If you happen to have a System Under Test that uses an API that your SUT adds a listener too, it can get a bit more complicated as well(You can do this same thing with executors and timers(mock both)).

class RealAPIYouSUTUses {
      public void addListener(XXXListener l);
}

class MockAPI implements RealAPIYourSUTUses{
      public void addListener(XXXListener l) {
         this.cachedListener = l;
      }
      public XXXListener getListener() {
         return cachedListener;
      } 
}

Then your unit test can test the listesner and it's interaction with the system...

class Test {
    public void test() {
        MockAPI mockAPI = new MockAPI();   
        SUT sut = new SUT(mockAPI);  

        sut.doSomething();
        //expect your listener to be added from calling doSomething....
        XXXListener l = mockApi.getListener();

        //simulate firing an event into your SUT 
        l.fireEvent(new Event("asdf"));
    }
}

The interesting thing about all this is you can mock Executor.java and Timer.java and your test can grab the runnable that was given to an executor and the TimerTaks to the Timer and you can run them in order and in reverse order to make sure your system works.

I do alot of asynchronous programming and unit testing like this rocks so you can make sure integration between all your classes is working.

Upvotes: 0

Klaus Byskov Pedersen
Klaus Byskov Pedersen

Reputation: 121037

It definitely looks like you are on the right track, but let me try to explain how I would go about the test.

The actual system under test (SUT) here is the Authenticate class. You have not told a lot about it, so I will assume the following:

It uses an instance of ICustomerRepository to determine the existence of a user based on a combination of username (email) and password.

When the repostiory returns an instance of Customer, given a username and password combination, the Login method returns true. When the repository returns null, the Login method returns false.

I will use these assumptions in the following, but if they are not correct, I´m sure you will be able to change the tests so that they make sense for your scenario.

Test 1: When the username/password combination is correct, Login will return true

public void LoginWillReturnTrueForAValidUsernamePasswordCombination()
{
    string email = "[email protected]";
    string password = "test";

    //Dummy customer
    var customer = new Customer();

    //Create mock
    var mockRepos = new Moq.Mock<ICustomerRepository>();
    mockRepos.Setup(x => x.GetCustomerByPasswordUsername(
            It.Is<string>(s => s == email), 
            It.Is<string>(s => s == password))
        .Returns(customer);

    var auth = new Authenticate(mockRepos.Object);

    //Act
    var result = auth.Login(email, password);

    //Assert
    Assert.IsTrue(result);
}

Note the use of It.Is. Basically, the mock is set up in a way that it will only return the dummy customer object when the email and password defined in your test are passed to the GetCustomerByPasswordUsername method.

Test 2: When the username/password combination is incorrect, Login will return false

public void LoginWillReturnFalseForAnInvalidUsernamePasswordCombination()
{
    string email = "[email protected]";
    string password = "test";

    //Create mock
    var mockRepos = new Moq.Mock<ICustomerRepository>();
    mockRepos.Setup(x => x.GetCustomerByPasswordUsername(
            It.Is<string>(s => s == email), 
            It.Is<string>(s => s == password))
        .Returns<Customer>(null);

    var auth = new Authenticate(mockRepos.Object);

    //Act
    var result = auth.Login(email, password);

    //Assert
    Assert.IsFalse(result);
}

Although implicitly tested by the above tests, you may want to go a step further and write a test that ensures that the Login method passes the right parameters to the repository. Such a test could look like the following:

Test 3: Login will invoke repository correctly

public void LoginWillInvokeGetCustomerByPasswordUsernameCorrectly()
{
    string email = "[email protected]";
    string password = "test";

    //Create mock
    var mockRepos = new Moq.Mock<ICustomerRepository>();
    mockRepos.Setup(x => x.GetCustomerByPasswordUsername(
            It.Is<string>(s => s == email), 
            It.Is<string>(s => s == password))
        .Returns<Customer>(null)
        .Verifiable();

    var auth = new Authenticate(mockRepos.Object);

    //Act (ignore result. We are only testing correct invocation)
    auth.Login(email, password);

    //Assert
    mockRepos.Verify();
}

The Verify method of a mock throws an exception if the methods that have been setup have not been called.

I hope this helps. Don't hesitate to ask if you have further questions.

Upvotes: 14

Related Questions