I have been starting unit testing recently and am wondering, should I be writing unit tests for 100% code coverage?
This seems futile when I end up writing more unit testing code than production code.
I am writing a PHP Codeigniter project and sometimes it seems I write so much code just to test one small function.
For Example this Unit test
public function testLogin(){ //setup $this->CI->load->library("form_validation"); $this->realFormValidation=new $this->CI->form_validation; $this->CI->form_validation=$this->getMock("CI_Form_validation"); $this->realAuth=new $this->CI->auth; $this->CI->auth=$this->getMock("Auth",array("logIn")); $this->CI->auth->expects($this->once()) ->method("logIn") ->will($this->returnValue(TRUE)); //test $this->CI->form_validation->expects($this->once()) ->method("run") ->will($this->returnValue(TRUE)); $_POST["login"]=TRUE; $this->CI->login(); $out = $this->CI->output->get_headers(); //check new header ends with dashboard $this->assertStringEndsWith("dashboard",$out[0][0]); //tear down $this->CI->form_validation=$this->realFormValidation; $this->CI->auth=$this->realAuth; } public function badLoginProvider(){ return array( array(FALSE,FALSE), array(TRUE,FALSE) ); } /** * @dataProvider badLoginProvider */ public function testBadLogin($formSubmitted,$validationResult){ //setup $this->CI->load->library("form_validation"); $this->realFormValidation=new $this->CI->form_validation; $this->CI->form_validation=$this->getMock("CI_Form_validation"); //test $this->CI->form_validation->expects($this->any()) ->method("run") ->will($this->returnValue($validationResult)); $_POST["login"]=$formSubmitted; $this->CI->login(); //check it went to the login page $out = output(); $this->assertGreaterThan(0, preg_match('/Login/i', $out)); //tear down $this->CI->form_validation=$this->realFormValidation; }
For this production code
public function login(){ if($this->input->post("login")){ $this->load->library('form_validation'); $username=$this->input->post('username'); $this->form_validation->set_rules('username', 'Username', 'required'); $this->form_validation->set_rules('password', 'Password', "required|callback_userPassCheck[$username]"); if ($this->form_validation->run()===FALSE) { $this->load->helper("form"); $this->load->view('dashboard/login'); } else{ $this->load->model('auth'); echo "valid"; $this->auth->logIn($this->input->post('username'),$this->input->post('password'),$this->input->post('remember_me')); $this->load->helper('url'); redirect('dashboard'); } } else{ $this->load->helper("form"); $this->load->view('dashboard/login'); } }
Where am I going so wrong?
Advertisement
Answer
In my opinion, it’s normal for test code to be more than production code. But test code tends to be straightforward, once you get the hang of it, it’s like a no brainer task to write tests.
Having said that, if you discover your test code is too complicated to write/to cover all the execution paths in your production code, that’s a good indicator for some refactoring: your method may be too long, or attempts to do several things, or has so many external dependencies, etc…
Another point is that it’s good to have high test coverage, but does not need to be 100% or some very high number. Sometimes there are code that has no logic, like code that simply delegates tasks to others. In that case you can skip testing them and use @codeCoverageIgnore
annotation to ignore them in your code coverage.