How can I guarantee that I will not break the test code when I reorganize it?

The code evolves, and it also breaks up, if not cropped, a bit like a garden in this regard. Downsizing means refactoring so that it fulfills its changing goal.

Refactoring is much safer if we have good unit test coverage. Test-based development forces us to write test code first before production code. Therefore, we cannot test the implementation because it does not exist. This greatly facilitates the reorganization of production code.

The TDD cycle looks something like this: write a test, a failed test, write a production code until the test succeeds, reorganize the code.

But from what I saw, people are reorganizing production code, but not test code. As the test code breaks down, the production code will become obsolete, and then everything goes down. Therefore, I think it is necessary for refactoring test code.

The problem here is: how do you guarantee that you will not break the test code when refactoring it?

(I did one approach, https://thecomsci.wordpress.com/2011/12/19/double-dabble/ , but I think there might be a better way.)

Obviously there is a book, http://www.amazon.com/dp/0131495054 , which I have not read yet.

There is also a Wiki page, http://c2.com/cgi/wiki?RefactoringTestCode , which has no solution.

+6
source share
5 answers

Refactoring your tests is a two-step process. Simply put: you must first use your application under testing to check if the tests pass when refactoring. Then, after your reorganized tests are green, you need to make sure that they fail. However, for this you need to follow certain steps.

To properly test your reorganized tests, you must modify the application under test to cause the test to fail. Only this verification condition should fail. In this way, you can ensure that the test does not work properly in addition to the transfer. You should aim for one test failure, but in some cases it will not be possible (i.e. Not unit tests). However, if you set up refactoring correctly, there will be one failure in refactored tests, and other failures will exist in tests that are not related to the current refactoring. Correct identification of cascading failures of this type requires an understanding of your code base, and errors of this type only apply to tests other than unit tests.

+1
source

I think you should not change your test code.

Why? In TDD, you define an interface for a class. This interface contains methods defined with a specific set of functionality. requirements / design .

First: These requirements do not change when refactoring your production code. Refactoring means: changing / cleaning code without changing functionality.
Second: The test checks a specific set of functions, this set remains the same.

Conclusion: Refactoring and refactoring your production code are two different things.

Tip. When you write your tests, write clean code. Do some small tests. Which really tests one element of functionality.

But "Your design is changing due to unforeseen requirements changes." This may or may not lead to changes in the interface.
When your requirements change, your tests must change. This cannot be avoided.
You should keep in mind that this is a new TDD cycle. First check out the new features and remove the old functionality tests. Then follow the new design.

To do it right, you need clean and small tests. Example:

MethodOne does: changeA and changeB Don't put this in 1 unit test, but make a test class with 2 unit tests. Both execute MethodOne, but they check for other results (changeA, changeB). When the specification of changeA changes, you only need to rewrite 1 unit method. When MethodOne gets a new specification changeC: Add a unit test. 

In the example above, your tests will be more flexible and easier to modify.

Summary:

  • Do not refactor your tests when refactoring your production code.
  • Write clean and flexible tests.

Hopes this helps. Good luck to you.

@disclaimer: I do not want your money if it makes you rich.

+2
source

Um.

FOR JAVA SOLUTION! I don’t know what language you are programming!

Well, I just read the Clean Code by one of Martins, a book that claims that the idea of ​​refactoring test code to maintain cleanliness and readability is a great idea, really the goal. So striving for refactoring and keeping the code clean is good, not a dumb idea, as I thought at first.

But this is not what you requested, so let's take a snapshot of the answer!

I would save the db of your tests - or the last test result. With a little java annotation, you can do something like this:

 @SuperTestingFramerworkCapable public class MyFancyTest { @TestEntry @Test public testXEqualsYAfterConstructors(){ @TestElement //create my object X @TestElement //create my object Y @TheTest AssertTrue(X.equals(Y)); } } 

ANYWAY, you will also need a superclass of the refusion and annotation class that will check this code. It may just be an extra step in your processing - write tests, go through this super processor, and then, if it passes, run the tests. And your super processor will use the MyFancyTest circuit

And for each member that you have in your class, it will use a new table - here the table (only) will be testXEqualsYAfterConstructors And this table will have columns for each element marked with the @TestElement annotation. And it will also have a column for @TheTest I suppose you just call the columns TestElement1, TestElement2, etc. Etc.

AND THEN, once he has installed all this, he will just save the variable names and the annotated @TheTest string. So the table will be

 testXEqualsYAfterConstructors TestElement1 | TestElement2 | TheTest SomeObjectType X | SomeObjectType X | AssertTrue(X.equals(Y)); 

So, if the super processor goes and finds that the tables exist, then it can compare what is already with what is now in the code, and can raise a warning for each individual record. And you can create a new user - the administrator, who can receive the changes, and can check them, the type of crucible is normal, or not.

And then you can sell this solution to this problem, sell you a company for 100 million and give me 20%

Hurrah!

A slow day, here's the rational: yuor's solution uses a lot of the extra overhead, most damagingly, in the actual production code. Your prod code should not be bound to your test code, and it certainly should not have a random variable that is specific to the test. The next suggestion that I have with the code you provided is that your structure does not stop people violating the tests. In the end, you can do this:

 @Test public void equalsIfSameObject() { Person expected = createPerson(); Person actual = expected; check(Person.FEATURE_EQUAL_IF_SAME_OBJECT); boolean isEqual = actual.equals(expected); assertThat(isEqual).isTrue(); } 

But if I changed the last two lines of code in some "refactoring" of test classes, then your structure will report success, but the test will do nothing. You really need to make sure the warning is raised and people can look at the “difference”.

Then again, you can simply use svn or perforce and the crucible to compare and verify this material!

In addition, seeing that you are interested in a new idea, you will want to read about local annotations: http://stackoverflow.com/questions/3285652/how-can-i-create-an-annotation- processor, what-processes-a local variable

Um, so you might need to get this guy - see the last comment in the link above - you may need his own java compiler.

@Disclaimer If you create a new company with a code that largely follows the above, I reserve the right to 20% of the company if and when you cost more than 30 million at the time of my choice

+1
source

How do you guarantee that you will not break the test code while refactoring this?

Retesting the tests should be sufficient in most cases.

There are other strategies described here , but they can be excessive compared to the few benefits that you get.

+1
source

About two months before your question became one of my main questions in refactoring. Just let me explain my experience:

  • when you want to reorganize a method, you should cover it with unit tests (or any other tests) to make sure you don't break something during refactoring (in my case, the team knew that the code worked well because they used it in for 6 years, they just needed to improve it, so all my unit tests passed in the first stage). So, in the first step, you have several passed unit tests that cover entire scenarios. If some of the unit tests fail, you must first fix this problem to make sure your method works correctly.

  • after passing all the tests, you reorganized the method and want to run the test to make sure that everything is correct. Any changes to the test codes?

  • You must write tests that are independent of the internal structure of the method. After refactoring, you just need to change a small part of the code, and in most cases no changes are required, since refactoring simply improves the structure and does not change the behavior. If your test code needs to be changed a lot, you never know that during refactoring you broke some things in the main code.

  • and the most important thing for me is to remember in each test, you need to consider one behavior

I hope I explain well.

+1
source

Source: https://habr.com/ru/post/904115/


All Articles