The simple answer here is that you need to cause an exception to be thrown.
The golden rule of unit testing is you only gain coverage for code that is executed as part of a test method. No exception means that you don't execute your
Why try to handle exceptions here?
If you aren't sure how to cause an exception to be thrown in this particular case, then that may be a sign that you shouldn't be attempting to handle exceptions. Part of the purpose of unit tests, after all, is to serve as a way to notify people when changes that they're trying to make will break existing functionality. If your batch apex works fine right now, the first sign of trouble in the future should be a failing test.
To me, it looks like your biggest concern here might be changes to validation, workflow, or process builder. One of the best practices for testing is to have a utility class to build instances of SObjects for your tests that satisfy all of your validation rules. Keeping the generic test data setup in a single location makes it easier to adapt to changes to validation rules (just modify the code in a single, well-known class).
If I haven't dissuaded you
There is a simple way to cause an exception to be thrown. Throw one yourself.
In the past, I've made use of
@testVisible private static Boolean forceException = false;
private modifier ensures that nobody can inadvertently cause exceptions in normal use. The
@testVisibleannotation ensures that you can control this value from a unit test.
The last piece of the puzzle is to include something like the following inside your
throw new System.DmlException('test exception');
With that, you have an exceedingly simple way to guarantee that an exception is thrown, when you want it to be thrown (and only when you want it to be thrown).
You're not done yet
Remember that the main purpose of unit tests is not simple coverage, but rather to verify that your code produces the expected output using assertions. Coverage is a side-effect of running tests (and happens to be the only thing Salesforce can use as a metric to enforce some baseline code quality).
Without assertions, you're simply testing to see that your code doesn't explode when run. While that is a good thing (code not exploding, that is), what would happen if your code ended up deleting some records that shouldn't be deleted?
As is, your test would not warn you that this happened. How long would it take for you (or someone) to realize that records had been deleted? Would someone realize this before the records would be removed from the recycle bin? Do you take snapshots of your Salesforce data?
If your code adds, removes, or modifies SObjects, or if it returns a value, or if it modifies the state of a class, it is a very good idea to make assertions to verify that those things have, in fact, happened.