I'm having a hard time understanding why there is only one test per function in most professional TDD code that I have seen
I'm assuming that you mean 'assert' when you say 'test'. In general, a test should only test a single 'use case' of a function. By 'use case' I mean: a path that the code can flow through via control flow statements (don't forget about handled exceptions, etc.). Essentially you are testing all of the 'requirements' of that function. For example, say you have a function such as:
Public Function DoSomething(ByVal foo as Boolean) As Integer
Dim result as integer = 0
If(foo) then
result = MakeRequestToWebServiceA()
Else
result = MakeRequestToWebServiceB()
End If
return result
End Function
In this case, there are 2 'use cases' or control flows that the function can take. This function should have at minimum 2 tests for it. One that accepts foo as true and branches down the if(true) code, and one that accepts foo as false and goes down the second branch. If you have more if statements or flows the code can go though, then it will require more tests. This is for several reason - the most important one to me is that without it, the tests would be too complicated and hard to read. There's other reasons too, like in the case of the above function, the control flow is based on input parameter - which means you must call the function twice to test all code paths. You should never call the function more then once that you are testing in your test IMO.
but I find myself struggling to come up with function names to differentiate the different tests since many are so similar
Maybe you are over-thinking it?? Don't be scared of writing crazy, overly verbose names for your test function. Whatever that test does, write it in english, use underscores, and come up with a set of standards for names so that someone else looking at the code (including yourself 6 months later) can easily figure out what it does. Remember, you never actually have to call this function yourself (at least in most testing frameworks), so who cares if the name of it is 100 characters. Go Crazy. In the above example, my 2 tests would be named:
DoSomethingTest_TestWhenFooIsTrue_RequestIsMadeToWebServiceA()
DoSomethingTest_TestWhenFooIsFalse_RequestIsMadeToWebServiceB()
Also - this is just a general guideline. There are definitely cases where you will have multiple asserts in the same unit test. This will happen when you are testing the same control flow, but multiple fields need to be checked when you write your assert statement(s). Take this for example - a test for a function which parses a CSV file into a business object which has a Header, a Body, and Footer field:
Public Sub ParseFileTest_TestFileIsParsedCorrectly()
Dim target as new FileParser()
Dim actual as SomeBusinessObject = target.ParseFile(TestHelper.GetTestData("ParseFileTest.csv")))
Assert.Equals(actual.Header,"EXPECTED HEADER FROM TEST DATA FILE")
Assert.Equals(actual.Footer,"EXPECTED FOOTER FROM TEST DATA FILE")
Assert.Equals(actual.Body,"TEST DATA BODY")
End Sub
Here, we are really testing the same use case, but we needed multiple asserts to check all our data and make sure our code actually worked.
-Drew