Furthermore side effects have nothing to do with testing one's code. Why? Because you have to test your own logic, not I/O or something else. I/O is already tested by someone else. So you actually don't care where the data comes from - the filesystem or a hardcoded string - you care if the output is correct after the respective transformations are applied to the input.
And when you think about it testing shouldn't be that needed at all. In the OOP world, where state and identity are helplessly tied together and we are not working with values, but with references to values, tests might be a necessary evil.
In the land of Functional however writing tests shouldn't be needed, at least in theory. Why? Because if you write small composable functions you should be able to test them right in the REPL. Corner cases? You have to think about them right from the start. TDD forces you to do so - then why shouldn't you when you have the immense power of a REPL? Once a function is ready you are not supposed to change it much. If you do you should change the inner workings and not the input/output. If you need to change the i/o most probably you need a different function. But what is more important is that if you needed to change the i/o and had tests for this function you would actually need to change the tests as well, which is more work (double? triple?) and no added value.