Jelajahi Sumber

Merge branch 'refector/better-mocking' into refactor/controllers

* refector/better-mocking:
  Test RecipeCardPanel.
  Clean up IngredientPanel.
  Fix warning in Preparation
  Alter PreparationPanelTest to properly use mocking/injection for tests.
Sam Jaffe 5 tahun lalu
induk
melakukan
752f22ad6d

+ 2 - 1
src/main/lombok/org/leumasjaffe/recipe/model/Preparation.java

@@ -12,9 +12,10 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
 
 import lombok.AllArgsConstructor;
 import lombok.Data;
+import lombok.EqualsAndHashCode;
 import lombok.NoArgsConstructor;
 
-@Data @AllArgsConstructor @NoArgsConstructor
+@Data @AllArgsConstructor @NoArgsConstructor @EqualsAndHashCode(callSuper=false)
 public class Preparation extends Observable.Instance implements RecipeComponent {
 	Duration duration;
 	@JsonIgnore Supplier<Collection<Ingredient>> producer = Collections::emptyList;

+ 1 - 1
src/main/lombok/org/leumasjaffe/recipe/model/RecipeCard.java

@@ -23,7 +23,7 @@ public class RecipeCard extends Observable.Instance implements CompoundRecipeCom
 	
 	@Override
 	public Stream<Element> getComponents() {
-		return elements.stream();
+		return getElements().stream();
 	}
 	
 	@Override

+ 5 - 2
src/main/lombok/org/leumasjaffe/recipe/view/DurationPanel.java

@@ -12,7 +12,7 @@ import org.leumasjaffe.recipe.model.Duration;
 @SuppressWarnings("serial")
 public class DurationPanel extends JPanel {
 	private JLabel lblTime;
-	public DurationPanel(String name, Duration duration) {
+	public DurationPanel(String name) {
 		GridBagLayout gridBagLayout = new GridBagLayout();
 		gridBagLayout.columnWidths = new int[]{0, 0, 0};
 		gridBagLayout.rowHeights = new int[]{0, 0};
@@ -32,7 +32,10 @@ public class DurationPanel extends JPanel {
 		gbc_lblTime.gridx = 1;
 		gbc_lblTime.gridy = 0;
 		add(lblTime, gbc_lblTime);
-		
+	}
+
+	public DurationPanel(String name, Duration duration) {
+		this(name);
 		setModel(duration);
 	}
 

+ 15 - 7
src/main/lombok/org/leumasjaffe/recipe/view/PreparationPanel.java

@@ -5,11 +5,11 @@ import javax.swing.JPanel;
 import org.jdesktop.swingx.VerticalLayout;
 import org.leumasjaffe.observer.ObservableListener;
 import org.leumasjaffe.recipe.controller.ReplaceChildrenController;
+import org.leumasjaffe.recipe.model.Duration;
 import org.leumasjaffe.recipe.model.Ingredient;
 import org.leumasjaffe.recipe.model.Preparation;
 
 import lombok.AccessLevel;
-import lombok.Getter;
 import lombok.experimental.FieldDefaults;
 
 import java.awt.GridBagLayout;
@@ -27,9 +27,9 @@ public class PreparationPanel extends JPanel {
 	ReplaceChildrenController<Preparation, Ingredient> controller;
 	ObservableListener<JPanel, Preparation> childListener;
 	
-	@Getter(AccessLevel.PACKAGE) JPanel panelIngredients;
+	DurationPanel panelDuration;
 		
-	public PreparationPanel(Preparation preparation) {
+	public PreparationPanel() {
 		controller = new ReplaceChildrenController<>(Preparation::getIngredients,
 				IngredientPreparationPanel::new);
 		
@@ -69,14 +69,14 @@ public class PreparationPanel extends JPanel {
 		gbc_horizontalGlue.gridy = 0;
 		panelLeft.add(horizontalGlue, gbc_horizontalGlue);
 		
-		DurationPanel panelDuration = new DurationPanel("Requires", preparation.getDuration());
+		panelDuration = new DurationPanel("Requires", Duration.ZERO);
 		GridBagConstraints gbc_panelDuration = new GridBagConstraints();
 		gbc_panelDuration.insets = new Insets(0, 0, 5, 0);
 		gbc_panelDuration.gridx = 2;
 		gbc_panelDuration.gridy = 0;
 		panelLeft.add(panelDuration, gbc_panelDuration);
 		
-		panelIngredients = new JPanel();
+		JPanel panelIngredients = new JPanel();
 		panelIngredients.setLayout(new VerticalLayout(5));
 		GridBagConstraints gbc_panelIngredients = new GridBagConstraints();
 		gbc_panelIngredients.gridwidth = 3;
@@ -85,11 +85,19 @@ public class PreparationPanel extends JPanel {
 		gbc_panelIngredients.gridx = 0;
 		gbc_panelIngredients.gridy = 1;
 		panelLeft.add(panelIngredients, gbc_panelIngredients);
-	
+		
 		// This indirection allows for testing of controller
 		childListener = new ObservableListener<>(panelIngredients,
 				(c, v) -> controller.accept(c, v));
-		
+	}
+	
+	public PreparationPanel(final Preparation preparation) {
+		this();
+		setModel(preparation);
+	}
+	
+	public void setModel(final Preparation preparation) {
+		panelDuration.setModel(preparation.getDuration());
 		childListener.setObserved(preparation);
 	}
 

+ 20 - 9
src/main/lombok/org/leumasjaffe/recipe/view/RecipeCardPanel.java

@@ -24,11 +24,14 @@ public class RecipeCardPanel extends JSplitPane {
 	ObservableListener<RecipeCardPanel, RecipeCard> updateUI;
 	ForwardingObservableListener<RecipeCard> listener;
 	
-	public RecipeCardPanel(final RecipeCard card) {
+	SummaryPanel summaryPanel;
+	JPanel rightPanel;
+	
+	public RecipeCardPanel() {
 		setPreferredSize(new Dimension(1050, 600));
 
-		final SummaryPanel summaryPanel = new SummaryPanel(card);
-		final JPanel rightPanel = new JPanel();
+		summaryPanel = new SummaryPanel();
+		rightPanel = new JPanel();
 		rightPanel.setLayout(new VerticalLayout(5));
 
 		final JScrollPane scrollPane = new JScrollPane(rightPanel);
@@ -36,14 +39,22 @@ public class RecipeCardPanel extends JSplitPane {
 		scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
 		setRightComponent(scrollPane);
 		setLeftComponent(summaryPanel);
-		
-		card.getComponents().map(ElementPanel::new).forEach(rightPanel::add);
-				
+						
 		listener = new ForwardingObservableListener<>();
-		listener.setObserved(card, card.getElements().toArray(new Element[0]));
-		
 		updateUI = new ObservableListener<>(this, (c, t) -> validate());
-		updateUI.setObserved(card);
+	}
+	
+	public RecipeCardPanel(final RecipeCard card) {
+		this();
+		setModel(card);
+	}
+	
+	public void setModel(final RecipeCard card) {
+		summaryPanel.setModel(card);
+		card.getComponents().map(ElementPanel::new).forEach(rightPanel::add);
+
+		listener.setObserved(card, card.getElements());
+		updateUI.setObserved(card);		
 	}
 
 }

+ 13 - 4
src/main/lombok/org/leumasjaffe/recipe/view/summary/IngredientPanel.java

@@ -27,7 +27,7 @@ public class IngredientPanel extends JPanel {
 	@Getter(AccessLevel.PACKAGE) JFormattedTextField txtAmount;
 	@Getter(AccessLevel.PACKAGE) JTextField txtUnit;
 	
-	public IngredientPanel(final Ingredient ingredient) {
+	public IngredientPanel() {
 		GridBagLayout gridBagLayout = new GridBagLayout();
 		gridBagLayout.columnWidths = new int[]{0, 0, 0, 0, 0};
 		gridBagLayout.rowHeights = new int[]{0, 0};
@@ -43,7 +43,7 @@ public class IngredientPanel extends JPanel {
 		gbc_label.gridy = 0;
 		add(label, gbc_label);
 		
-		txtName = new JTextField(ingredient.getName());
+		txtName = new JTextField();
 		txtName.setEditable(false);
 		txtName.setFont(new Font("Source Code Pro", Font.PLAIN, 10));
 		GridBagConstraints gbc_txtName = new GridBagConstraints();
@@ -59,7 +59,6 @@ public class IngredientPanel extends JPanel {
 		fmtDone.setCommitsOnValidEdit(true);
 		txtAmount = new JFormattedTextField(fmtDone);
 		txtAmount.setEditable(false);
-		txtAmount.setValue(ingredient.getAmount().getValue());
 		txtAmount.setFont(new Font("Source Code Pro", Font.PLAIN, 10));
 		GridBagConstraints gbc_txtAmount = new GridBagConstraints();
 		gbc_txtAmount.fill = GridBagConstraints.HORIZONTAL;
@@ -69,7 +68,7 @@ public class IngredientPanel extends JPanel {
 		add(txtAmount, gbc_txtAmount);
 		txtAmount.setColumns(4);
 		
-		txtUnit = new JTextField(ingredient.getAmount().unitName());
+		txtUnit = new JTextField();
 		txtUnit.setEditable(false);
 		txtUnit.setFont(new Font("Source Code Pro", Font.PLAIN, 10));
 		GridBagConstraints gbc_txtUnit = new GridBagConstraints();
@@ -81,4 +80,14 @@ public class IngredientPanel extends JPanel {
 		txtUnit.setColumns(6);
 	}
 
+	public IngredientPanel(final Ingredient ingredient) {
+		this();
+		setModel(ingredient);
+	}
+	
+	public void setModel(final Ingredient ingredient) {
+		txtName.setText(ingredient.getName());
+		txtAmount.setValue(ingredient.getAmount().getValue());
+		txtUnit.setText(ingredient.getAmount().unitName());
+	}
 }

+ 16 - 6
src/main/lombok/org/leumasjaffe/recipe/view/summary/SummaryPanel.java

@@ -30,7 +30,10 @@ public class SummaryPanel extends JPanel {
 	ObservableListener<CollatedDurationPanel, RecipeCard> durationListener;
 	ObservableListener<JPanel, RecipeCard> childListener;
 	
-	public SummaryPanel(final RecipeCard card) {
+	JTextField txtTitle;
+	JTextArea txaDesription;
+	
+	public SummaryPanel() {
 		controller = new ReplaceChildrenController<>(RecipeCard::getElements, element -> {
 			JPanel wrapper = new JPanel(new VerticalLayout());
 			wrapper.add(new ElementPanel(element));
@@ -60,8 +63,7 @@ public class SummaryPanel extends JPanel {
 		gbl_panelHeader.rowWeights = new double[]{0.0, 0.0, Double.MIN_VALUE};
 		panelHeader.setLayout(gbl_panelHeader);
 		
-		JTextField txtTitle = new JTextField();
-		txtTitle.setText(card.getTitle());
+		txtTitle = new JTextField();
 		GridBagConstraints gbc_txtTitle = new GridBagConstraints();
 		gbc_txtTitle.insets = new Insets(0, 0, 0, 5);
 		gbc_txtTitle.fill = GridBagConstraints.HORIZONTAL;
@@ -107,11 +109,10 @@ public class SummaryPanel extends JPanel {
 		gbc_panelPhoto.gridy = 0;
 		panel.add(panelPhoto, gbc_panelPhoto);
 		
-		JTextArea txaDesription = new JTextArea(5, 20);
+		txaDesription = new JTextArea(5, 20);
 		txaDesription.setFont(new Font("Verdana", Font.PLAIN, 10));
 		txaDesription.setWrapStyleWord(true);
 		txaDesription.setLineWrap(true);
-		txaDesription.setText(card.getDescription());
 		GridBagConstraints gbc_txaDesription = new GridBagConstraints();
 		gbc_txaDesription.insets = new Insets(0, 0, 5, 0);
 		gbc_txaDesription.fill = GridBagConstraints.BOTH;
@@ -125,7 +126,16 @@ public class SummaryPanel extends JPanel {
 		// This indirection allows for testing of controller
 		childListener = new ObservableListener<>(panelIngredients,
 				(c, v) -> controller.accept(c, v));
-		
+	}
+	
+	public SummaryPanel(final RecipeCard card) {
+		this();
+		setModel(card);
+	}
+	
+	public void setModel(final RecipeCard card) {
+		txtTitle.setText(card.getTitle());
+		txaDesription.setText(card.getDescription());
 		durationListener.setObserved(card);
 		childListener.setObserved(card);
 	}

+ 25 - 26
src/test/java/org/leumasjaffe/recipe/view/PreparationPanelTest.java

@@ -1,58 +1,57 @@
 package org.leumasjaffe.recipe.view;
 
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.collection.IsArrayWithSize.arrayWithSize;
 import static org.mockito.Mockito.*;
 
-import java.util.Arrays;
-
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
-import org.junit.platform.runner.JUnitPlatform;
-import org.junit.runner.RunWith;
 import org.leumasjaffe.observer.ObserverDispatch;
-import org.leumasjaffe.recipe.model.Amount;
+import org.leumasjaffe.recipe.controller.ReplaceChildrenController;
 import org.leumasjaffe.recipe.model.Duration;
 import org.leumasjaffe.recipe.model.Ingredient;
 import org.leumasjaffe.recipe.model.Preparation;
-import org.mockito.Spy;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
 import org.mockito.junit.jupiter.MockitoExtension;
 
 @ExtendWith(MockitoExtension.class)
-@RunWith(JUnitPlatform.class)
 class PreparationPanelTest extends SwingTestCase {
 	
-	@Spy Preparation stuff;
-	PreparationPanel panel;
+	@Mock DurationPanel panelDuration;
+	@Mock ReplaceChildrenController<Preparation, Ingredient> controller;
+	Preparation stuff;
+	@InjectMocks PreparationPanel panel = new PreparationPanel();
 	
 	@BeforeEach
 	void setUp() {
+		stuff = mock(Preparation.class);
 		Duration dur = new Duration(Duration.Display.SECONDS, 0, 30);
 		doReturn(dur).when(stuff).getDuration();
-		doReturn(Arrays.asList(
-				new Ingredient("Butter", "", new Amount("10 g")),
-				new Ingredient("Salt", "", new Amount("0.25 tsp"))
-				)).when(stuff).getIngredients();
-
-		panel = new PreparationPanel(stuff);
+		
+		panel.setModel(stuff);
 	}
 
 	@Test
 	void testHasContent() {
-		assertThat(panel.getPanelIngredients().getComponents(),
-				arrayWithSize(2));
+		verify(panelDuration).setModel(any());
+		verify(controller, times(1)).accept(any(), same(stuff));
+	}
+
+	@Test
+	void testDoesNotUpdateDurationWhenNotified() {
+		clearInvocations(panelDuration);
+
+		ObserverDispatch.notifySubscribers(stuff);		
+
+		verify(panelDuration, never()).setModel(any());
 	}
 
 	@Test
 	void testUpdatesNumberOfChildrenWhenNotified() {
-		doReturn(Arrays.asList(
-				new Ingredient("Salt", "", new Amount("0.25 tsp"))
-				)).when(stuff).getIngredients();
+		clearInvocations((Object) controller);
 		
-		ObserverDispatch.notifySubscribers(stuff);
-		
-		assertThat(panel.getPanelIngredients().getComponents(),
-				arrayWithSize(1));
+		ObserverDispatch.notifySubscribers(stuff);		
+
+		verify(controller, times(1)).accept(any(), same(stuff));
 	}
 }

+ 67 - 0
src/test/java/org/leumasjaffe/recipe/view/RecipeCardPanelTest.java

@@ -0,0 +1,67 @@
+package org.leumasjaffe.recipe.view;
+
+import static org.mockito.Mockito.*;
+
+import java.awt.Component;
+import java.util.Arrays;
+
+import javax.swing.JPanel;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.leumasjaffe.mock.MockObserverListener;
+import org.leumasjaffe.observer.ObserverDispatch;
+import org.leumasjaffe.recipe.model.Element;
+import org.leumasjaffe.recipe.model.RecipeCard;
+import org.leumasjaffe.recipe.view.summary.SummaryPanel;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Spy;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+@ExtendWith(MockitoExtension.class)
+class RecipeCardPanelTest {
+	
+	@Spy MockObserverListener listener;
+	
+	@Mock SummaryPanel summaryPanel;
+	@Mock JPanel rightPanel;
+	@Spy RecipeCard card;
+	@InjectMocks RecipeCardPanel panel = new RecipeCardPanel();
+	
+	@BeforeEach
+	void setUp() {
+		listener.setObserved(card);
+		clearInvocations(listener);
+	}
+
+	@Test
+	void testModelIsPropogated() {
+		panel.setModel(card);
+		verify(summaryPanel).setModel(same(card));
+		verify(rightPanel, never()).add(any(Component.class));
+	}
+
+	@Test
+	void testModelWithChildrenAddsElements() {
+		final Element element = new Element();
+		doReturn(Arrays.asList(element)).when(card).getElements();
+
+		panel.setModel(card);
+		verify(rightPanel, times(1)).add(any(Component.class));
+	}
+
+	@Test
+	void testToChildElementsIsPropogated() {
+		final Element element = new Element();
+		doReturn(Arrays.asList(element)).when(card).getElements();
+
+		panel.setModel(card);
+		verify(listener).updateWasSignalled();
+		
+		ObserverDispatch.notifySubscribers(element);
+		verify(listener, times(2)).updateWasSignalled();
+	}
+
+}