views:

103

answers:

3

Hi,

Disclaimer: This is my first time writing unit tests...be gentle! :)

I am trying to write a test for the following method and would like people's thoughts an whether I am thinking about this the correct way. I have an interface called IAuthenticationProvider with the following method:

bool Authenticate(string username, string password)

I also have a class called UserAccountService that has the following method:

bool SignIn(string username, string password)

The UserAccountService takes a IAuthenticationProvider interface as part of the constructor and is used within the SignIn method. The SignIn method looks a little like:

public bool SignIn(string username, string password)
{
    // _provider is of type IAuthenticationProvider
    bool result = _provider.Authenticate( username, password );  
    // ....
    return result;
}

Initially when I thought of tests such as "signing in with unknown username", "signing in with an invalid password", etc. But, I then began to think that I don't really want to test the "authentication" aspect, i.e. _provider.Authenticate, but I want to test the actual signing in. So, I thought tests such as "signining in while already signed in", "signing in when the user cannot be authenticated", etc, would make more sense.

Would this be the right way of approaching this these type of tests?

Kind Regards

Michael

+1  A: 

You test the authentication in the tests for the IAuthenticationProvider class. That is assumed to work. In SignIn() you have to consider the _provider as perfect (any trouble will be tested somewhere else in your testsuite) and test the SignIn routine.

However, you must test everything that has been tested for IAuthProvider on the SignIn method as well. That will give you the additional coverage that your information is actually passed correctly to _provider, and its result is properly returned.

Stefano Borini
Simple or not the implementation could be:public bool SignIn(string username, string password){ return true }and all your test are still happy. My treshold of things I do think are not breakable goes down constantly. :-)
Thomas Jung
I think you are right :)
Stefano Borini
Would it actually be possible, or needed, to perform the IAuthProvider tests again in the SignIn method? The SignIn method is only really interested in the possible true/false values of the Authenticate method.
Michael
+2  A: 

You can use a mock-based test. This would setup a UserAccountService with a mock implementation of IAuthenticationProvider.

//happy case provider return true
mock = createMock(IAuthenticationProvider, true);
service = new UserAccountService(mock).SignIn(..);
...

//provider will return false
mock = createMock(IAuthenticationProvider, false);
service = new UserAccountService(mock).SignIn(..);
...

You can write your own mock implementations if you like. Most of the time it is easier to use a mock library as easymock:

//same as above
mock = createMock(IAuthenticationProvider.class)
expect(mock.Authenticate(...)).andReturn(true);
replay(mock)
service = new UserAccountService(mock).SignIn(..);
//test here

Mock tests have their own cost and should only be used when a state-based test is not possible. Your application design should be in a way that classes depend on as few classes as possible and can be ideally work on their own (plus your runtime).

Thomas Jung
I like the idea of using a mocking framework and keeping the testing of the "authentication" elsewhere. I'll give this approach a try.
Michael
I don't usually use Mock object. I use real object whenever possible. If you change the implementation of IAuthenticationProvider one day, you will have to check and change all your test cases that use mock object. You must make sure the mock object your created reflects the functionality of real object. What a maintenance nightmare.
janetsmith
If you look at this example you'll see that the mock object depends on the interface and not on the implementation of that interface. The mock has only to be able to reproduce this. It does not depend on the implementation knowledge when to accept. The mock has to change when the interface contract changes.
Thomas Jung
A: 

I agree that you should not be unit testing the authentication aspect in SignIn, since that is actually happening in the provider.

If all the SignIn method is doing is what is shown above, returning the result from _provider.Authenticate, then the only tests that make any sense for that particular method are pretty trivial, to verify that it returns False for a False from _provider.Authenticate and True for a True from _provider.Authenticate. Pass in mock providers with known results to the constructor for the testing.

If "signing in while already signed in" and "signing in when the user cannot be authenticated" is handled in your SignIn method but not shown above, then yes, makes sense to test them there. But not if they are done elsewhere. For unit tests, you only want to test what the particular unit is responsible for.

Anon