What is the difference between a seam and a layout?

For several months since I work with legacy java code, these are some of the things I deal with:

  • 0% testing coverage.
  • Huge functions in cases I even saw some with over 300 lines of code.
  • Many private methods and static methods in cases.
  • Very hard code.

In the beginning, I was very confused, it was difficult for me to use TDD as a legacy. After riding around for weeks and practicing my unit tests and bullying skills, my fear decreased and I feel a little more confident. I recently discovered a book called: working with heritage , I didn’t read it, I just looked at the table of contents, and I discovered something new for me, Stitches. Apparently, this is very important when working in the legacy.

I think these stitches can help me break the dependencies and make my code visible so that I can increase the reach of the code and make my unit test more accurate.

But I have many doubts:

  • Can someone explain to me the difference between seam and layout?
  • Do Seams, violate TDD rules for not touching production code before it has been tested?
  • Could you show me a simple example comparing Seam and Mock?

Below I would like to insert the example that I did today when I tried to break the dependency in order to test the code and, finally, increase the test coverage. I would appreciate if you could comment a little if you see some errors?

Here is the source code at the beginning:

public class ABitOfLegacy { private String sampleTitle; String output; public void doSomeProcessing(HttpServletRequest request) { String [] values = request.getParameterValues(sampleTitle); if (values != null && values.length > 0) { output = sampleTitle + new Date().toString() + values[0]; } } } 

If I just add a unit test, which calls this method and asserts this variable output, has a certain value after the call, then I would be wrong because I am not testing the module, I would do integration testing, So what I need to do is get rid of the dependency that I have in the parameter. To do so, I replace the parameter with an interface:

 public class ABitOfLegacy { private String sampleTitle; String output; public void doSomeProcessing(ParameterSource request) { String [] values = request.getParameters(sampleTitle); if (values != null && values.length > 0) { output = sampleTitle + new Date().toString() + values[0]; } } } 

Here's what the interface looks like:

 public interface ParameterSource { String[] getParameters(String name); } 

The next thing I do is create my own implementation of this interface, but I turn on the HttpServletRequest as a global variable and implement the interface method using the / s HttpServletRequest method:

 public class HttpServletRequestParameterSource implements ParameterSource { private HttpServletRequest request; public HttpServletRequestParameterSource(HttpServletRequest request) { this.request = request; } public String[] getParameters(String name) { return request.getParameterValues(name); } } 

Up to this point, I believe that all modifications to the production code were safe. Now I am creating Seam in my test suite. If I understood well, now I can safely change the behavior of the seam. Here is how I do it:

 public class FakeParameterSource implements ParameterSource { public String[] values = {"ParamA","ParamB","ParamC"}; public String[] getParameters(String name) { return values; } } 

And the last step would be to get support from Seam to test the original behavior of the method.

 import org.junit.Before; import org.junit.Test; import static org.junit.Assert.*; import static org.mockito.Mockito.*; import code.ABitOfLegacyRefactored; import static org.hamcrest.Matchers.*; public class ABitOfLegacySpecification { private ABitOfLegacy aBitOfLegacy; private String EMPTY = null; @Before public void initialize() { aBitOfLegacy = new ABitOfLegacy(); } @Test public void the_output_gets_populated_when_the_request_is_not_empty () { FakeParameterSource fakeParameterSource = new FakeParameterSource(); aBitOfLegacy.doSomeProcessing(fakeParameterSource); assertThat(aBitOfLegacy.output,not(EMPTY)); } @Test(expected=NullPointerException.class) public void should_throw_an_exception_if_the_request_is_null () { aBitOfLegacy.doSomeProcessing(null); } } 

This will give me 100% coverage. I appreciate your thoughts:

  • Did I break the addiction correctly?
  • Are unit tests missing?
  • What can be done better?
  • Is this example good enough to help me understand the difference between a seam and a layout?
  • How could I scoff if I don't use a seam?
+6
source share
2 answers

Stitches

A seam is a place that allows you to change behavior without changing the code.

In your example below is an example of an object seam (if I'm not mistaken). It allows you to transfer another object without changing the code. therefore, it is a type of seam.

 public void doSomeProcessing(ParameterSource request) {..} 

Having made the parameter abstract (instead of a specific class), you entered a seam. The seam now allows you to change the behavior of a method without editing its code - that is, at the place of the call, I can transfer another object and make a way to do something else.

Mocks

Now instead of creating a custom fake (creating an interface subtype) you could use the Mock framework to do something like this

Mocks also supports the assertion whether specific methods were called on it, argument comparisons, and other excellent functionality that should be used in testing. Less test code to support. Mocks is mainly used to claim that a particular call is made for dependency. In your example, you seem to need a Stub, you just want to return a canned value.

Sorry my rusty jmock ..

  @Test public void the_output_does_not_get_populated_when_the_request_is_empty () { Mockery context = new Mockery(); final ParameterSource mockSource = context.mock(ParameterSource.class) context.checking(new Expectations(){{ oneOf(mockSource).getParameters(); will(returnValue(new string[]{"ParamA","ParamB","ParamC"} ); }}); aBitOfLegacy.populate(mockSource); assertThat(aBitOfLegacy.output,not(EMPTY)); } 

in .Net

 var mockSource = new Mock<ParameterSource>(); mockSource.Setup(src => src.GetParameters()) .Returns(new []{"ParamA","ParamB","ParamC"}); 
+4
source

A seam is a place in the code where you can insert a behavior modification. You created a seam when setting up the attachment of your dependency.

One way to use the seam is to insert some kind of fake. The fake can be manual, as in your example, or created using a tool such as Mockito.

So, the layout is a type of fake, and fake is often used using a seam.

As for your tests and how you broke the addiction, how much I would do it.

+7
source

All Articles